【问题解析】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,主进程关句柄没用,端口被内核锁定,改为独立进程、关闭句柄继承即可彻底解决。

相关推荐
zylyehuo2 小时前
Linux系统中网线与USB网络共享冲突
linux
Quz6 小时前
QML Hello World 入门示例
qt
博客18001 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴1 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
Sokach10151 天前
Linux Shell 脚本从零到能用:一个新手的一天学习总结
linux
AlfredZhao2 天前
Docker 容器时区不对,`timedatectl` 不存在怎么办?
linux·timezone
众少成多积小致巨2 天前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
zzzzzz3103 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
xcyxiner3 天前
DicomViewer (dcmtk读取dcm文件)5
qt
XIAOHEZIcode3 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏