[每日一题]获取当前机器正在Listen的端口

本文介绍了一种在高负载机器上监控监听端口的高效方法,避免使用netstat和nmap带来的性能瓶颈,通过直接读取/proc/net/tcp等文件来获取所有正在监听的端口,并提供了实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求来源

我们正在编写一个监控系统,在每个机器上会部署一个监控的agent,这个agent需要获取当前机器所有正在listen的端口汇报给server,每30s汇报一次

常见做法

你的第一时间反应可能是netstat命令,但是在连接数比较多(比如达到几十万)的机器上,运行netstat根本跑不出结果。 那么使用nmap?注意我的需求,采集当前机器上面所有正在Listen的端口,那用nmap的话可能需要从1~65535这么扫描一遍,发syn包?这样会造成很多半开连接,直接创建tcp连接并最终关闭?也会耗费太多资源,而且我还需要每30s汇报一次! - 在机器本身负载很重的情况下:(

我认知中的最好方案

读取/proc/net/{tcp,tcp6,udp,udp6}这四个文件,其实zabbix就是这么干的,通过匹配字符串的方式可以直接拿到所有Listening的端口

/proc/net/tcp简介

cat /proc/net/tcp | less 可以看到有个st字段,即状态字段,它的值和对应的解释:

00  "ERROR_STATUS",
01  "TCP_ESTABLISHED",
02  "TCP_SYN_SENT",
03  "TCP_SYN_RECV",
04  "TCP_FIN_WAIT1",
05  "TCP_FIN_WAIT2",
06  "TCP_TIME_WAIT",
07  "TCP_CLOSE",
08  "TCP_CLOSE_WAIT",
09  "TCP_LAST_ACK",
0A  "TCP_LISTEN",
0B  "TCP_CLOSING",

嗯,看到0A的解释了吧,TCP_LISTEN,找的就是它! 通常的做法就是逐行匹配: 00000000:0000 0A ,而local_address一栏冒号后面的部分就是端口号,采用16进制表示

注意

了解到以上信息,那我们是不是就可以逐行匹配获取了呢?理论上这样是可以的,但是……这个文件非常大,逐行匹配会非常耗费cpu资源,我们当时的情况,是差点吃掉一个核,影响了线上业务!怎么办呢?再告诉你一个秘密: /proc/net/tcp这个文件会把Listen状态的连接放在文件开头部分 (一般人我不告诉他)。so:我们顺次读取匹配,第一行标题过滤掉,匹配一行获取一个port,一旦匹配不上了,也就直接break出for循环即可

参考代码

https://github.com/UlricQin/falcon/blob/master/collector/portstat.go

更新

最后发现ss -tln是个更好地选择,我们之前的做法还是有些问题,因为/proc/net/tcp真心不好读,时刻在变化,而且连接数多的时候读取起来很慢

本文转自:http://blog.ulricqin.com/article/listening-port-monitor

转载于:https://my.oschina.net/morflameblog/blog/266956

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值