【问题解析】Socket已经关闭了,但是端口还处于listening状态?

最近在上手一个QT项目的时候,在windows下用C++实现了一个服务器功能,开启50000-50008端口进行TCP监听,用来和另一个工具进行交互,服务器要求能动态创建和删除。但是在实际测试的时候发现我的服务器有的时候删不掉,即使socket已经关闭了,但是端口还是处于LISTENING的状态。

最开始的时候我的排查思路一直在线程资源没有回收掉上,下断点发现线程确实已经退出了,socket也关闭掉了,处于无效值状态了。也尝试在套接字的选项上进行了一些修改,结果都无济于事。我甚至一度开始怀疑windows下socket使用上是不是有什么隐藏的机制。

由于这个问题的出现很有规律,是客户端再向我的服务器的50001-50008端口发送消息之后,才会导致所有端口关不掉,我就将关闭服务器的代码不断地切换位置,想确认一下是到哪个位置才关闭不掉了。发现是客户端向我的服务器发送消息之后,我的服务器会开启tftpd32进程来准备传输数据,而我是通过子进程的方式创建的tftpd32进程,瞬间恍然大悟了。我将创建的方式修改为了单独进程的方式,果然可以顺利关闭掉端口了。

那整个问题就变成了 "为什么我开了服务器之后,创建一个子进程,这时候咋在主进程里面就关闭不掉服务器了?"

核心根因:Windows套接字内核引用共享机制

Windows 系统中,Socket 套接字本质是内核对象,并不是单纯的进程私有资源。 当在主进程创建 TCP 监听 Socket(50000~50008)后,通过子进程方式启动 tftpd32 时:

  1. Windows 默认继承父进程所有内核句柄(Socket、文件句柄、网络句柄等);

  2. TCP 监听 Socket 句柄,被 tftpd32 子进程隐性继承;

  3. 此时,同一个监听端口的 Socket 内核对象,同时存在两个进程引用:主进程 和 tftpd32子进程

为什么关 Socket、关线程都没用?

  1. 在主进程中:正常关闭 Socket 句柄、销毁服务对象、退出监听线程; 仅仅只关闭了「主进程」的 Socket 引用;

  2. 但 tftpd32 子进程依然持有该 Socket 内核句柄;

  3. Windows 端口释放机制:只有占用端口的所有进程,全部关闭 Socket 句柄,端口才会解除 LISTENING 状态; 只要还有任意一个进程持有该监听 Socket 句柄,内核就会保留端口监听,端口永久占用、无法释放。 这就是看到的现象: 主进程 socket 已关闭、线程已销毁、变量置空,但端口依然挂在 LISTENING,删不掉服务。

为什么「改为独立进程」就正常了?

我修改了进程启动方式,脱离子进程继承机制、以独立进程启动 tftpd32:

  • 关闭了句柄继承特性;
  • tftpd32 进程不会继承父进程的 TCP 监听 Socket 句柄;
  • 主进程关闭 Socket 时,该内核对象唯一引用被释放;
  • 内核正常回收端口, LISTENING 状态解除,服务可正常销毁。

补充:QT / Windows 解决方案

  1. 创建子进程时,禁用句柄继承 Windows 创建子进程时,设置句柄不可继承,从根源杜绝;

  2. 临时屏蔽网络句柄继承

  3. 独立进程启动第三方工具

总结

Windows 下 Socket 是内核句柄,子进程默认继承父进程所有网络句柄;tftpd32 子进程偷占了监听端口 Socket,主进程关句柄没用,端口被内核锁定,改为独立进程、关闭句柄继承即可彻底解决。

相关推荐
爱丶狸13 小时前
Grafana_Zabbix_ImageRenderer_部署与前端操作手册
linux·前端·zabbix·grafana·kylin
隐积13 小时前
3.1.7.Qt容器大家族(3):QVariant——万能盒子
开发语言·qt
k4m7v2pz14 小时前
把 Bevy 0.14 游戏移植到 R36S 掌机:一场与“无窗口系统“的搏斗
linux·rust·bevy·r36s·rk3326·开源掌机
Tri_Function15 小时前
动态规划DP1(c++)
c++
木子欢儿16 小时前
Intel 架构的 MacBook Pro 运行 Linux 发热量高解决
linux·运维·服务器
清水迎朝阳18 小时前
客户端软件 — 用户统计方案
服务器·c++·客户端·用户统计
会编程的土豆19 小时前
Go 模板初识
linux·运维·服务器
腾讯蓝鲸智云19 小时前
标杆客户实践提炼:CFlow 版本价值流模板实战指南
运维·服务器·自动化·云计算·devops
阿标的博客19 小时前
Active Directory 组织单位和用户
服务器
再卷也是菜19 小时前
C++17(下)
c++