我可以验证连接是否已建立:
$ netstat -tn | grep "192.168.2.110"
tcp 0 0 192.168.2.100:10444 192.168.2.110:52639 ESTABLISHED
有没有办法检查这个 tcp 端口连接已经打开(连接)多长时间了?
(不,我无权访问应用程序日志)
答案1
您可以尝试以下操作:
通过添加选项来获取
$pid
程序的PID(比如说) 。-p
netstat
/proc/net/tcp
通过查看local_address
和/或字段来识别文件中的正确行rem_address
(请注意,它们是十六进制格式,特别是 IP 地址以小端字节顺序表示),还要确保是st
(01
对于ESTABLISHED
(英文):注意相关
inode
字段(例如$inode
);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")
}
例子:
$ suptime 93.184.216.34 80
Thu Dec 24 16:22:58 CET 2015 (46.12s ago)
答案2
这个问题对我很有帮助,但是我发现使用lsof
而不是netstat
让我避免所有的 HEX 东西:
${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")
答案4
感谢 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
}
笔记:
- 需求
bc
, (由rhel >= 7 和类似系统netstat
提供)net-tools
- 需要以 root 身份运行