如何确定Linux上的套接字连接正常运行时间


24

我可以验证连接是否正常:

$ netstat -tn | grep "192.168.2.110"
tcp  0  0 192.168.2.100:10444  192.168.2.110:52639  ESTABLISHED

有没有办法检查此tcp端口连接建立(连接)的时间?

(不,我无权访问应用日志)

Answers:


23

您可以尝试以下方法:

  1. $pid通过将-p选项添加到来获得程序的PID(例如)netstat

  2. /proc/net/tcp通过查看local_address和和/或rem_address字段来确定文件中的正确行(请注意,它们是十六进制格式,特别是IP地址以小尾数字节顺序表示),还应确保st01(用于ESTABLISHED);

  3. 注意相关inode字段(例如$inode);

  4. 搜索是inode在文件描述符中/proc/$pid/fd终于查询符号链接的文件访问时间:

    find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %t
    

这是一项艰巨的工作...这是一个脚本(存根),用于自动化上述几点,它需要远程地址,并在几秒钟内显示套接字的正常运行时间:

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}
    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")
    # get the PID of the owner process
    local pid=$(netstat -ntp 2>/dev/null | awk '$6 == "ESTABLISHED" && $5 == "'$addr:$port'"{sub("/.*", "", $7); print $7}')
    [ -z "$pid" ] && { echo 'Address does not match' 2>&1; return 1; }
    # get the inode of the socket
    local inode=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inode" ] && { echo 'Cannot lookup the socket' 2>&1; return 1; }
    # query the inode status change time
    local timestamp=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %T@)
    [ -z "$timestamp" ] && { echo 'Cannot fetch the timestamp' 2>&1; return 1; }
    # compute the time difference
    LANG=C printf '%s (%.2fs ago)\n' "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
}

(感谢Alex修复,进行编辑)

例:

$ suptime 93.184.216.34 80
Thu Dec 24 16:22:58 CET 2015 (46.12s ago)

1
此配方显示创建TCP连接的进程的年龄,而不是连接本身的年龄。
myroslav 2015年

您确定@myroslav吗?它适用于此Node.js脚本
cyrus

我已经使用Firefox在64位Fedora 22上通过Firefox打开的TCP连接测试了您的新脚本,但是我肯定没有获得“正常运行时间”数字。当新的套接字打开时,它将获得“随机”的正常运行时间,通常是“最年轻的”已建立套接字的时间。
myroslav 2015年

@myroslav我在这里使用Debian(3.16.0-4-amd64),我唯一注意到的是报告的时间实际上比套接字创建要晚3秒。也许涉及一些与系统有关的行为...
cYrus

对于脚本,“ $ suptime 192:168:120:10 6379追溯(最近一次调用最近):文件” <string>“,<module>套接字中的第1行。错误:非法IP地址字符串传递给inet_aton地址确实不匹配”
OndraŽižka17年

4

这个问题对我很有帮助,但是我发现使用lsof而不是netstat让我避免使用所有十六进制的东西:

对于${APP}用户运行的进程${USER},以下内容将所有打开的套接字返回到IP地址$ {IP}:

PEEID=$(sudo pgrep -u ${USER} ${APP}) && for i in `sudo lsof -anP -i -u logstash | grep ${IP} | awk '{print $6}'` ; do echo "${device} time" ; sudo find /proc/${PEEID}/fd -lname "socket:\[${device}\]" -printf %t 2> /dev/null  ; echo  ;  done

lsof包含PID,但我不确定如何获取它以及设备号。

已在Amazon Linux上进行了测试。


3

cYrus编写的脚本对我有用,但我必须对其进行一些修复(以摆脱十六进制地址中的“ L”并使端口成为4位十六进制):

--- suptime.orig    2015-08-20 15:46:12.896652464 +0200
+++ suptime 2015-08-20 15:47:48.560074728 +0200
@@ -7,8 +7,8 @@
     hex_addr=$(python -c "
 import socket, struct;
 print hex(struct.unpack('<L',
-socket.inet_aton('$addr'))[0])[2:].upper().zfill(8)")
-    hex_port=$(python -c "print hex($port)[2:].upper()")
+socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8)")
+    hex_port=$(python -c "print hex($port)[2:].upper().zfill(4)")
     inode=$(awk '$3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
     time=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %A@)
     LANG=C printf '%.2fs' $(bc <<<"$(date +%s.%N) - $time")

1

怎么样:

lsof -t -i @ 192.168.2.110 | xargs ps -fp

您还可以定制“ ps”命令以获取pid并使用-o开始时间,例如:

lsof -t -i @ 192.168.2.110 | xargs ps-无标题-o'pid,start'-p

当然,这假定套接字是在进程启动时启动的。


这显示了打开套接字的过程需要多长时间。如果某个进程一直运行并且网络断开,则这些值将有很大的不同。+1的努力
hidralisk

1

感谢您在cYrus的答案中维护的脚本。我在打印重复项时遇到问题,可能是因为从不同的PID到提供的地址可能存在许多连接,所以这是我的改进版本,它还在每条输出线上打印PID:

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}

    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")

    # get the inode of the socket
    local inodes=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inodes" ] && { echo 'Cannot lookup the socket(s)' 2>&1; return 1; }

    # get file descriptors
    for inode in $inodes; do
        # get inode's file descriptor details
        local fdinfo=( $(find /proc/[0-9]*/fd -lname "socket:\[$inode\]" -printf "%p %T@") )
        [ -z "$fdinfo" ] && { echo 'Cannot find file descriptor' 2>&1; return 1; }

        # extract pid
        local fdpath=${fdinfo[0]}
        local pid=${fdpath#/proc/}
        pid=${pid%%/*}

        # extract timestamp
        local timestamp=${fdinfo[1]}

        # compute the time difference
        LANG=C printf 'PID: %s; Age: %s (%.2fs ago)\n' "$pid" "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
    done
}

笔记:

  • 需求bcnetstat(由net-toolsrhel> = 7和类似系统提供)
  • 需要以root身份运行
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.