如何找到哪个进程绑定了一个套接字但不监听?
Posted
技术标签:
【中文标题】如何找到哪个进程绑定了一个套接字但不监听?【英文标题】:how to find which process bind a socket but not listen? 【发布时间】:2018-11-23 17:42:10 【问题描述】:当我使用 nc 监听一个端口时,它会显示
nc -l -vv -p 21000
retrying local 0.0.0.0:21000 : Address already in use Can't grab 0.0.0.0:21000 with bind
但是我用工具 netstat / ss 找不到哪个任务占用了这个端口
netstat -an|grep 21000
;没有找到
ss -a|grep 21000
;没有找到
这个端口被我的java程序占用了,代码是:
public class Test1
public static void main(String[] args) throws InterruptedException
Socket s = new Socket();
try
s.bind(new InetSocketAddress("127.0.0.1",21000));
catch (IOException e)
e.printStackTrace();
Thread.sleep(500000000000L);
当我绑定一个套接字时,不要将它与连接或监听一起使用。 我进入 /proc/[java task id]/fd ,发现这个socket的inode是“socket:[3073501]” 但即使在 /proc/net/tcp 或 /proc/net/tcp6 中我也找不到 inode 或端口
有什么方法可以找到绑定socket但不监听或连接的进程。
谢谢。
我看到了 linux 3.10.0-327 源代码。我认为文件/proc/net/tcp 的内容来自net/ipv4/tcp_ipv4.c。
在 tcp_proc_register 方法中,
static void *tcp_get_idx(struct seq_file *seq, loff_t pos)
void *rc;
struct tcp_iter_state *st = seq->private;
st->state = TCP_SEQ_STATE_LISTENING;
rc = listening_get_idx(seq, &pos);
if (!rc)
st->state = TCP_SEQ_STATE_ESTABLISHED;
rc = established_get_idx(seq, pos);
return rc;
它只显示正在侦听或从 tcp_hashinfo 建立的袜子。但是 tcp_hashinfo 有三个结构
struct inet_bind_hashbucket *bhash;
struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE];
struct inet_ehash_bucket *ehash;
bhash 可用于绑定。 但是不会在 /proc/net/tcp 中导出。
【问题讨论】:
哇。我可以完全按照描述重现这个问题,这不是与/proc/net/tcp
样式十六进制表示法或基于/etc/services
的名称的简单混淆。我也找不到lsof
的端口号。 nc -l
仍然说它正在使用中,与发布的完全一样。
简单的解决方案是不要写那样的代码,确定吗?通常你会立即连接Socket
,而且绑定它通常没什么意义。
How to investigate ports opened by a certain process in linux?、Find original owning process of a Linux socket、How to kill a process running on particular port in Linux?、How do I find and kill process running on a certain port? 等可能重复
@jww 令人惊讶的是,这些都不适用
【参考方案1】:
我在 Ubuntu 下测试了你的 Java 程序。
如何找到绑定socket但不监听也不连接的进程:
lsof
lsof | grep "can't identify protocol"
你会得到如下结果:
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 29644 29653 stephan 12u sock 0,7 0t0 312066 can't identify protocol
请注意类型sock
和名称can't identify protocol
。
这是如何工作的?看看lsof的FAQ:
为什么基于 /proc 的 lsof 报告某些套接字文件“无法识别协议”?
/proc-based lsof 可能会报告:
COMMAND PID ... TYPE ... NODE NAME pump 226 ... sock ... 309 can't identify protocol
这意味着它无法识别协议(即 AF_* 指定)被打开的套接字文件使用。 Lsof 标识 协议通过匹配与关联的节点号 /proc//fd 条目到在选定文件中找到的节点号 /proc/net 子目录。
...
您可能无法找到所需的节点号,因为并非所有 内核协议模块完全支持 /proc/net 信息。
验证过程
lsof 输出中的 PID 为 29644。
ls -l /proc/29644/fd
导致:
...
lrwx------ 1 stephan stephan 64 Jul 7 22:52 11 -> socket:[312064]
lrwx------ 1 stephan stephan 64 Jul 7 22:52 12 -> socket:[312066]
...
和
grep 312066 /proc/net/*
给出一个空结果。
【讨论】:
我的lsof
显示27401296 protocol: TCP
和TCP *:21000 (LISTEN)
否则(没有“无法识别协议”)。这并不理想,因为它不允许查看哪个程序保留哪个端口,但至少这可以识别一些候选者!
是的,使用第二列中 PID 的 lsof 输出,您只能获得潜在的候选人。但应该不会太多。该问题应该仅在两种情况下出现:套接字已绑定但未侦听/连接或使用后未正确关闭套接字。我发现你的 lsof 输出很有趣。我需要看看我明天是否可以更新我的 lsof 版本。
这是来自 Debian 测试的 4.89。以上是关于如何找到哪个进程绑定了一个套接字但不监听?的主要内容,如果未能解决你的问题,请参考以下文章