我该如何找出本地套接字的另一端是哪个程序?

20
我的Linux系统上有一个进程,使用strace告诉我它在与文件描述符10对应的套接字通信。lsof告诉我这是一个带有inode 11085的Unix套接字,而netstat进一步告诉我inode 11085是一个流套接字,并且它已连接。 考虑到该进程没有其他线程,因此必须有另一个进程连接到此套接字的另一端。我该如何找到它是哪个进程? 更新:从lsof的作者这里得到了一些启示。本质上,似乎Linux没有提供这个信息。

1
一个进程即使没有线程,也可以拥有套接字的两个端口。 - sigjuice
1
正确。但在这种情况下,它正在轮询套接字并定期唤醒,因此必须有其他东西将其唤醒。 - daf
8个回答

12
ss -p

会告诉你。(前提是该套接字不属于内核本身。)


在Debian上,/usr/bin/ss位于iproute2软件包中。 - daf
1
这对我的情况没有帮助,但因为它简单并且在IP和Unix套接字方面运行良好,所以将其标记为正确。 - daf
问题是关于本地套接字的。-1 - Parker Kemp
很遗憾我不能给你两颗星。这个问题已经困扰我好几个月了...现在我可以完成我的指南http://www.linuxintro.org/wiki/Strace - Thorsten Staerk

7

你是否需要使用netstat -p命令?

来自Manpage:

  -p,
  --program Show the PID and name of the program to which each socket belongs.

不幸的是,这是busybox netstat,所以它不支持-p选项。但是节点11085在netstat输出中只出现一次,因此似乎它只属于我已知的进程。 - daf
@daf 你应该在你的问题中提到使用busybox(也许还要加一个标签)。 - lothar
Busybox确实有一个配置选项来支持-p开关。请参见选项CONFIG_FEATURE_NETSTAT_PRG,通过busybox menuconfig选择Networking Utilities → netstat → Enable PID/Program name output进行选择。 - Craig McQueen

5
这样怎么样:grep 11085 /proc/net/unix。假设您感兴趣的inode所在的行中存在非空路径,则可以在/proc/net/unix上搜索该路径以查找连接另一端的inode,然后使用@efficientjelly的方法将其他inode映射到pid。关键点在于两个连接套接字各自具有不同的inode号码。

真狡猾!我不知道/proc/net/unix。可惜,这个套接字没有关联的路径。 - daf

2

我观察到:

在客户端调用connect()时,文件描述符fd的Inode始终比服务器端accept()调用返回的Inode多1。

我的程序示例输出:

client_fd=4
/proc/4436/fd/4
inode=3072
is socket
node: 3072 socket: /tmp/unix.socket
f0be8960: 00000003 00000000 00000000 0001 03  3072 /tmp/unix.socket

/proc/9293/fd/43
fd:43
inode=3073
is socket
node: 3073 socket: 
f0be81e0: 00000003 00000000 00000000 0001 03  3073

绑定路径虽然不会在/proc/net/unix中显示。
你的情况可能有所不同,我没有调查其底层机制。

+1,不幸的是看起来唯一的获取结果的方法就是...! - Kevin
(抱歉,我太快回复了,这在我的计算机上没有验证) - Kevin
大多数情况下有效,但不可靠(请参见我的答案 - lemonsqueeze

2
我编写了一个工具,它使用gdb方法可靠地获取套接字对等端信息,无需内核调试符号。
要获取连接到给定套接字的进程,请传递它的inode号:
# socket_peer 11085
3703 thunderbird 

一起查找所有进程,请使用netstat_unix,它会在netstat的输出中添加一列:
# netstat_unix
Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Peer PID/Program name  Path
unix  3      [ ]         STREAM     CONNECTED     6825     982/Xorg             1497/compiz            /tmp/.X11-unix/X0
unix  3      [ ]         STREAM     CONNECTED     6824     1497/compiz          982/Xorg                 
unix  3      [ ]         SEQPACKET  CONNECTED     207142   3770/chromium-brows  17783/UMA-Session-R       
unix  3      [ ]         STREAM     CONNECTED     204903   1523/pulseaudio      3703/thunderbird       
unix  3      [ ]         STREAM     CONNECTED     204902   3703/thunderbird     1523/pulseaudio           
unix  3      [ ]         STREAM     CONNECTED     204666   1523/pulseaudio      3703/thunderbird       
...

如果您需要易于解析的输出,请尝试netstat_unix --dump
有关详细信息,请参见https://github.com/lemonsqueeze/unix_sockets_peers
顺便说一下,inode +1/-1 hack并不可靠。它大多数情况下都有效,但如果运气不好,它将失败或(更糟糕的是)返回错误的套接字。

2
看起来如果你真的很绝望,你可以通过使用一些内核调试器直接从Linux内核内存中获取该信息。使用RHEL5的“crash”工具:
- 获取未压缩的vmlinux映像(例如安装kernel-debuginfo rpm或从该rpm中提取vmlinux文件) - 运行crash /path/to/vmlinux - net -s 12345列出PID为12345的所有套接字 - 找到有趣的套接字(必须是UNIX:STREAM家族/类型),并注意其SOCK值:
- PID: 12345 TASK: e903d000 CPU: 0 COMMAND: "someapp" - FD SOCKET SOCK FAMILY:TYPE SOURCE-PORT DESTINATION-PORT - 36 cadd0240 c8a64040 UNIX:STREAM - 现在你拥有了这个套接字的unix_sock struct的地址
- 基本上,unix_sock.peer.name是套接字另一端的名称结构 - 使用:p *(*(*((struct unix_sock*)( (struct unix_sock*)0xc8a64040)->peer)).addr).name打印它
真的很遗憾这些信息不直接导出到用户空间。

2

如果您使用适当的lsof和netstat选项仍然无法解决问题,您还可以执行以下操作:

find /proc -lname '*11085*' 2> /dev/null

1
聪明!由于系统只有busybox find,-lname无法工作,但我们可以模拟它:$ for i in find /proc -type l; do readlink "$i" | grep -q 11085 && echo "$i"; done /proc/1892/task/1892/fd/10 /proc/1892/fd/10因此,只有原始进程出现。 - daf

0

lsof | grep 11085

需要以root身份执行lsof。

我一直在我的Linux系统上尝试使用lsof,lsof -U显示列NODE下的所有数字都是唯一的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接