我有一个 java 和 cpp 客户端应用程序,它在 Linux 上运行并创建到服务器的 TCP 连接。这些应用程序在建立 TCP 连接后修改这些 TCP 连接的 Keepalive 参数(即 Linux 默认的 Keepalive 7200 秒从特定 TCP 连接的应用程序修改为 300)。
$cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
$cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
$cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
消费者保护计划
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, 300, sizeof(int));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, 60, sizeof(int));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, 5, sizeof(int));
爪哇
sslSocket.setOption(ExtendedSocketOptions.TCP_KEEPIDLE, 300);
sslSocket.setOption(ExtendedSocketOptions.TCP_KEEPINTERVAL, 60);
sslSocket.setOption(ExtendedSocketOptions.TCP_KEEPCOUNT, 5);
我的问题 有没有办法从 Linux 终端查看特定于已建立的 TCP 连接(对于这些应用程序创建的特定连接)的保持活动间隔/延迟/探测计数值是多少。
一旦我确定了从应用程序建立的特定 TCP 连接,我想打印这些特定连接的保持活动值(并验证这些 TCP 连接是否具有我从应用程序设置的保持活动值,而不是操作系统默认值)。
答案1
TCP Keep-alive 单独存在于两个对等点上(它们不协商也不知道对方的设置)。因此,如果客户端设置了保持活动状态,则可以(仅)在客户端上进行检查
使用 (rt)netlink 套接字的较新工具(至少)可以部分获取该信息:在 Linux 上ss
已过时。netstat
当前状态是可检索的,而不是套接字配置。
例如,客户端已建立到主机 192.0.2.4 端口 5555 的连接,并将保持活动空闲时间设置为 120 秒。可以socat
这样重现:
socat -d -d tcp4:192.0.2.4:5555,keepalive=1,keepidle=120 -
人们可以使用附加-e / --extended
选项ss
(在内核 5.17.x 和ip路由25.18.0):
$ ss -tne dst == 192.0.2.4 and dport == 5555
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
ESTAB 0 0 192.0.2.3:40498 192.0.2.4:5555 timer:(keepalive,1min58sec,0) uid:1000 ino:4007748 sk:432 cgroup:/user.slice/user-1000.slice/session-2.scope <->
这里:timer:(keepalive,1min58sec,0)
是有关套接字当前保持活动状态的信息。由于连接后大约 2 秒完成,因此显示 1 分 58 秒。此处不提供 2mn 初始配置。
对于简单的应用程序,我们可以使用 GDB 之类的调试器工具来注入getsockopt(2)
系统调用来检索和显示给定套接字上的配置(还需要 的ss
选项-p
来检索 PID(可能是共享此套接字的多个 PID)和 FD插座)。这是我在此问答中的一个示例,其中信息不适用于给定的内核:如何找到tap接口与其文件描述符之间的联系?
但是对于像 java 这样的多线程应用程序,它在 futex 和 co 的线程之间使用了大量的同步,我不确定在它上面使用调试器可能不会产生由定时中断引起的副作用。
答案2
我不认为有是一种从我所知道的任何 shell 中执行此操作的方法。ss
它本身甚至无法显示此信息 - 它可能只是进程状态,未通过任何有意义的方式导出到任何其他进程。
因此,“工具化调试器”可能是实现这一点的唯一方法:
ptrace
-附加到该目标进程,停止它;然后[做gdb
什么call
确实,即保存一点状态,建立一个堆栈,设置正确的寄存器,然后将指令指针设置为getsockopt
,运行直到弹出最后一个堆栈帧,处理结果,恢复状态和原始指令指针并继续运行。
这不是你可以从 shell 中完成的事情!