最可靠方式是调用ss -tuln命令而非硬解析/proc/net文件,因后者易漏UDP、IPv6及防火墙过滤端口;C++中应使用popen()读取输出,过滤通配绑定并提取十进制端口。

Linux下用netstat或ss命令获取监听端口最可靠
直接调用系统命令是C++里最稳定、兼容性最好的方式,因为内核网络状态不通过标准API暴露给用户态程序,硬编码解析/proc/net/文件容易漏掉UDP、IPv6或被防火墙过滤的端口。
推荐优先用ss -tuln(比netstat更快、更现代):
ss -tuln | awk 'NR>1 {print $5}' | cut -d: -f2 | sort -u实际在C++中执行时注意:
-
std::system()会阻塞,且无法捕获输出;改用popen()配合fgets()读取结果更可控 - 记得过滤掉
*:*和::*:这种通配绑定,只保留具体端口号 - 某些容器环境(如Docker无特权模式)可能禁止
ss访问/proc/net/,需提前验证权限
C++读取/proc/net/tcp和/proc/net/udp要手动解析十六进制地址
Linux下这些文件每行格式固定,但端口号以十六进制大端存储,比如00000000:01BB中的01BB对应十进制443。
立即学习“C++免费学习笔记(深入)”;
关键步骤包括:
将提醒同步至 Windows/Outlook 日历。用户提及「提醒我」「设置提醒」「加到日历」「同步到日历」「日程」「calendar」「日历」时触发。支持Microsoft Graph API 设备代码流认证,无需 Web 服务器,直接写入用户 Outlook 日历。
- 跳过第一行表头,逐行读取
- 用
sscanf(line.c_str(), "%*d: %*x:%hx", &port)提取十六进制端口字段(注意%hx匹配unsigned short) - 第4列状态码:TCP的
0A表示LISTEN,UDP该列恒为07(无需判断状态) - IPv6对应文件是
/proc/net/tcp6和/proc/net/udp6,需分别打开处理
Windows上必须用GetExtendedTcpTable和GetExtendedUdpTable
Win32 API不提供类似Linux的伪文件系统,只能调用iphlpapi.h里的函数,且需要管理员权限才能看到其他用户的监听端口。
常见坑点:
- 第一次调用返回
ERROR_INSUFFICIENT_BUFFER,必须先用NULL参数获取所需缓冲区大小 - 返回结构体中
dwLocalPort已经是主机字节序,不用再ntohs() - UDP表没有状态字段,TCP表中
dwState为MIB_TCP_STATE_LISTEN才有效 - 编译时需链接
iphlpapi.lib,否则链接失败报LNK2019
跨平台封装建议:避免自己拼接字符串解析,优先用现成库
自己实现跨平台端口扫描容易在边界情况出错——比如ss输出格式随版本微调、Windows不同系统版本API行为差异、IPv6地址嵌入式冒号导致字段偏移。
更省心的做法:
- Linux/macOS:用
libpcap抓包反推活跃端口(适合运行时检测,非静态监听列表) - 全平台:集成
libstatgrab或轻量级psutil的C++绑定(如psutil-cpp),它内部已处理好各系统差异 - 若必须手写,至少把解析逻辑隔离到独立函数,按
#ifdef _WIN32分条件编译,别混在一起
真正麻烦的不是读数据,而是确认“已开启”到底指什么——是socket处于LISTEN状态?还是有进程正在向该端口发送数据?后者需要结合连接跟踪或流量分析,远超单纯枚举范围。

















