C语言 查找 Linux 套接字的原始拥有进程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2358518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:41:45  来源:igfitidea点击:

Find original owning process of a Linux socket

clinuxsockets

提问by Rob H

In Linux and other UNIX-like operating systems, it is possiblefor two (or more) processes to share an Internet socket. Assuming there is no parent-child relationship between the processes, is there any way to tell what process originally created a socket?

在Linux和其他类UNIX操作系统,它是可能的两个(或多个)进程共享一个互联网插座。假设进程之间没有父子关系,有什么办法可以判断最初是哪个进程创建了socket?

Clarification:I need to determine this from "outside" the processes using the /procfilesystem or similar. I can't modify the code of the processes. I can already tell what processes are sharing sockets by reading /proc/<pid>/fd, but that doesn't tell me what process originally created them.

澄清:我需要从使用/proc文件系统或类似系统的进程“外部”确定这一点。我无法修改进程的代码。我已经可以通过阅读来判断哪些进程正在共享套接字/proc/<pid>/fd,但这并不能告诉我最初是哪个进程创建了它们。

回答by whoplisp

You can use netstat for this. You should look in the columns 'Local Address' and 'PID/Program name'.

您可以为此使用 netstat。您应该查看“本地地址”和“PID/程序名称”列。

xxx@xxx:~$ netstat -tulpen
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 127.0.0.1:4005          0.0.0.0:*               LISTEN      1000       68449       7559/sbcl       
tcp        0      0 0.0.0.0:6000            0.0.0.0:*               LISTEN      0          3938        -               
tcp6       0      0 :::6000                 :::*                    LISTEN      0          3937        -               
udp        0      0 0.0.0.0:68              0.0.0.0:*                           0          4528        -               

回答by Cypher

doesn't 'lsof -Ua' help?

'lsof -Ua' 没有帮助吗?

回答by nos

You can likely find the shared sockets by parsing /proc/net/tcp (and similar "files" for other protocols). There's some docs on /proc/net/tcp here.

您可能可以通过解析 /proc/net/tcp(以及其他协议的类似“文件”)来找到共享套接字。有上的/ proc /净/ TCP一些文档在这里

You would need to find the socket (perhaps by its IP addresses/port numbers ?) and parse out the inode number. Once you have the inode, you can search through all of /proc/*/fd/*, calling statfor every link and inspect the st_inomember of struct statuntil you find a match.

您需要找到套接字(可能通过其 IP 地址/端口号?)并解析出 inode 号。拥有 inode 后,您可以搜索所有/proc/*/fd/*,调用stat每个链接并检查 的 st_ino成员,struct stat直到找到匹配项。

The inode number should match between the 2 processes, so when you've gone through all /proc/*/fd/*you should have found them both.

两个进程之间的 inode 编号应该匹配,因此当您完成所有操作后,/proc/*/fd/*您应该都找到了它们。

If what you do know is the process id and socket fd of the first, you might not need to go through /proc/net/tcp, all you need to do is stat the /proc/<pid>/fd/<fd>and search the rest of /proc/*/fd/*for a matching inode. You'd need /proc/net/tcp if you want to fetch the ip addresses/port number though - which you can find if you know the inode number

如果您知道的是第一个的进程 ID 和套接字 fd,则您可能不需要通过 /proc/net/tcp,您需要做的就是统计/proc/<pid>/fd/<fd>并搜索其余部分以/proc/*/fd/*查找匹配的 inode。如果你想获取 IP 地址/端口号,你需要 /proc/net/tcp - 如果你知道 inode 号,你可以找到它

回答by kbulgrien

For purposes creating a test case, consider a situation where multiple ssh-agentprocesses are running and have open sockets. I.e. A user runs ssh-agentmultiple times and loses the socket/PID information given when the agent started:

出于创建测试用例的目的,请考虑多个ssh-agent进程正在运行并打开套接字的情况。即用户ssh-agent多次运行并丢失代理启动时给出的套接字/PID信息:

$ find /tmp -path "*ssh*agent*" 2>/dev/null
/tmp/ssh-0XemJ4YlRtVI/agent.14405
/tmp/ssh-W1Tl4i8HiftZ/agent.21283
/tmp/ssh-w4fyViMab8wr/agent.10966

Later, the user wants to programmatically determine the PID owner of a particular ssh-agent socket (i.e. /tmp/ssh-W1Tl4i8HiftZ/agent.21283):

稍后,用户希望以编程方式确定特定 ssh-agent 套接字的 PID 所有者(即 /tmp/ssh-W1Tl4i8HiftZ/agent.21283):

$ stat /tmp/ssh-W1Tl4i8HiftZ/agent.21283
  File: '/tmp/ssh-W1Tl4i8HiftZ/agent.21283'
  Size: 0               Blocks: 0          IO Block: 4096   socket
Device: 805h/2053d      Inode: 113         Links: 1
Access: (0600/srw-------)  Uid: ( 4000/ myname)   Gid: ( 4500/   mygrp)
Access: 2018-03-07 21:23:08.373138728 -0600
Modify: 2018-03-07 20:49:43.638291884 -0600
Change: 2018-03-07 20:49:43.638291884 -0600
Birth: -

In this case, because ssh-agentnamed its socket nicely as a human onlooker can guess that the socket belongs to PID 21284, because the socket name contains a numeric component that is one-off from a PID identified with ps:

在这种情况下,因为ssh-agent很好地命名了它的套接字,因为旁观者可以猜测该套接字属于 PID 21284,因为套接字名称包含一个数字组件,它与标识为 的 PID 是一次性的ps

$ ps -ef |  grep ssh-agent
myname   10967     1  0 16:54 ?        00:00:00 ssh-agent
myname   14406     1  0 20:35 ?        00:00:00 ssh-agent
myname   21284     1  0 20:49 ?        00:00:00 ssh-agent

It seems highly unwise to make any assumption that the PIDs will be so reliable as to always only be off by one, but also, one might suppose that not all socket creators will name the sockets so nicely.

假设 PID 如此可靠以至于总是只关闭一个,这似乎是非常不明智的,而且,人们可能会认为并非所有套接字创建者都会如此好地命名套接字。

@Cypher's answer points to a straightforward solution to the problem of identifying the PID of the socket owner, but is incomplete as lsofactually can only identify this PID with elevated permissions. Without elevated permissions, no results are forthcoming:

@Cypher 的回答指出了识别套接字所有者的 PID 问题的直接解决方案,但不完整,因为lsof实际上只能识别具有提升权限的 PID。没有提升的权限,不会有结果:

$ lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283
$

With elevated permissions, however, the PID is identified:

但是,使用提升的权限,可以识别 PID:

$ sudo lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283
COMMAND     PID    USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
ssh-agent 21284 myname     3u  unix 0xffff971aba04cc00      0t0 1785049 /tmp/ssh-W1Tl4i8HiftZ/agent.21283 type=STREAM

In this case, the owner of the PID (myname) and socket was the one doing the query, so it seemed elevated permissions should not be needed. Furthermore, the task performing the query was not supposed to be able to elevate permissions, so I looked for another answer.

在这种情况下,PID (myname) 和套接字的所有者是执行查询的人,因此似乎不需要提升权限。此外,执行查询的任务不应该能够提升权限,所以我寻找了另一个答案。

This led me to @whoplisp's answer proposing netstat -tulpenas a solution to the OP's problem. While it may have been effective for the OP, the command line is too restrictive to serve as a general purpose command and was completely ineffective in this case (even with elevated permissions).

这让我想到了@whoplisp 的答案,提出netstat -tulpen作为 OP 问题的解决方案。虽然它可能对 OP 有效,但命令行限制太多,无法用作通用命令,并且在这种情况下完全无效(即使具有提升的权限)。

$ sudo netstat -tulpen | grep -E -- '(agent.21283|ssh-agent)'
$

netstat, however, can come close if a different command-line is used:

netstat但是,如果使用不同的命令行,则可以接近:

$ netstat -ap | grep -E -- '(agent.21283)'
(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)
unix  2      [ ACC ]     STREAM     LISTENING     1785049  -                    /tmp/ssh-W1Tl4i8HiftZ/agent.21283

Sadly, here too, the PID is elusive without elevated permissions:

可悲的是,如果没有提升的权限,PID 也是难以捉摸的:

$ sudo netstat -ap | grep -E -- '(agent.21283|ssh-agent)'
unix  2      [ ACC ]     STREAM     LISTENING     1765316  10967/ssh-agent      /tmp/ssh-w4fyViMab8wr/agent.10966
unix  2      [ ACC ]     STREAM     LISTENING     1777450  14406/ssh-agent      /tmp/ssh-0XemJ4YlRtVI/agent.14405
unix  2      [ ACC ]     STREAM     LISTENING     1785049  21284/ssh-agent      /tmp/ssh-W1Tl4i8HiftZ/agent.21283

Of the two solutions, however, lsofclearly wins at the races:

然而,在这两种解决方案中,lsof显然在比赛中获胜:

$ time sudo netstat -ap | grep -E -- '(agent.21283|ssh-agent)' >/dev/null

real    0m5.159s
user    0m0.010s
sys     0m0.019s
$ time sudo lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283 >/dev/null

real    0m0.120s
user    0m0.038s
sys     0m0.066s

Yet another tool exists according to the netstatman page:

根据netstat手册页存在另一个工具:

$ man netstat | grep -iC1 replace
NOTES
       This program is mostly obsolete.  Replacement for netstat is ss.  Replacement for netstat -r is ip route.  Replacement for netstat -i
       is ip -s link.  Replacement for netstat -g is ip maddr.

Sadly, ssalso requires elevated permissions to identify the PID, but, it beats both netstatand lsofexecution times:

可悲的是,ss也需要更高的权限来识别PID,但是,它打败既netstatlsof执行时间:

$ time sudo ss -ap | grep -E "(agent.21283|ssh-agent)"
u_str  LISTEN     0      128    /tmp/ssh-w4fyViMab8wr/agent.10966 1765316               * 0                     users:(("ssh-agent",pid=10967,fd=3))
u_str  LISTEN     0      128    /tmp/ssh-0XemJ4YlRtVI/agent.14405 1777450               * 0                     users:(("ssh-agent",pid=14406,fd=3))
u_str  LISTEN     0      128    /tmp/ssh-W1Tl4i8HiftZ/agent.21283 1785049               * 0                     users:(("ssh-agent",pid=21284,fd=3))

real    0m0.043s
user    0m0.018s
sys     0m0.021s

In conclusion, it might seem that for some PID identification, it appears that elevated permissions are required.

总之,对于某些 PID 标识,似乎需要提升权限。

Note: Not all operating systems require elevated permissions. For example, SCO Openserver 5.0.7's lsofseemed to work just fine without elevating permissions.

注意:并非所有操作系统都需要提升的权限。例如,SCO Openserver 5.0.7lsof似乎没有提升权限就可以正常工作。

Caveat: This answer may fail with respect to the OP's qualification for finding "the original creator" of the socket. In the example used, no doubt PID 21283 was the originator of the socket's creation as this PID is identified in the socket name. Neither lsofnor netstatidentified PID 21283 as the original creator, though clearly PID 21284 is the current maintainer.

警告:就 OP 寻找套接字“原始创建者”的资格而言,此答案可能会失败。在使用的示例中,毫无疑问 PID 21283 是套接字创建的发起者,因为该 PID 在套接字名称中标识。既没有lsof也没有netstat确定 PID 21283 是原始创建者,尽管很明显 PID 21284 是当前的维护者。

回答by Steve Emmerson

I don't know about using sendmsg() to "send" a socket from one process to another.

我不知道如何使用 sendmsg() 将套接字从一个进程“发送”到另一个进程。

I do know that the bind() system-call will return EADDRINUSE if a second process attempts to use the same port.

我知道如果第二个进程尝试使用相同的端口,bind() 系统调用将返回 EADDRINUSE。