2024年3月22日发(作者:)

当使用 Socket 进行通信时,由于各种不同的因素,都有可能导致死连接停留在

服务器端,假如服务端需要处理的连接较多,就有可能造成服务器资源严重浪费,

对此,本文将阐述其原理以及解决方法。

在写 Socket 进行通讯时,我们必须预料到各种可能发生的情况并对其进行处

理,通常情况下,有以下两种情况可能造成死连接:

通讯程序编写不完善

网络/硬件故障

a) 通讯程序编写不完善

这里要指出的一点就是,绝大多数程序都是由于程序编写不完善所造成的死连

接,即对 Socket 未能进行完善的管理,导致占用端口导致服务器资源耗尽。当

然,很多情况下,程序可能不是我们所写,而由于程序代码的复杂、杂乱等原因

所导致难以维护也是我们所需要面对的。

网上有很多文章都提到 Socket 长时间处于 CLOSE_WAIT 状态下的问题,说可

以使用 Keepalive 选项设置 TCP 心跳来解决,但是却发现设置选项后未能收到

效果 。

因此,这里我分享出自己的解决方案:

Windows 中对于枚举系统网络连接有一些非常方便的 API:

GetTcpTable : 获得 TCP 连接表

GetExtendedTcpTable : 获得扩展后的 TCP 连接表,相比 GetTcpTable 更为强大,可

以获取与连接的进程 ID

SetTcpEntry : 设置 TCP 连接状态,但据 MSDN 所述,只能设置状态为 DeleteTcb,

即删除连接

相信大多数朋友看到这些 API ,就已经了解到我们下一步要做什么了;枚举

所有 TCP 连接,筛选出本进程的连接,最后判断是否 CLOSE_WAIT 状态,如果

是,则使用 SetTcpEntry 关闭。

其实 Sysinternal 的 TcpView 工具也是应用上述 API 实现其功能的,此工

具为我常用的网络诊断工具,同时也可作为一个简单的手动式网络防火墙。

下面来看 Zealic 封装后的代码:

/**

$Rev: 0 $

**/

using System;

using c;

using stics;

using ;

using kInformation;

using pServices;

namespace k

{

///

/// TCP 管理器

///

public static class TcpManager

{

#region PInvoke define

private const int TCP_TABLE_OWNER_PID_ALL = 5;

[DllImport("", SetLastError = true)]

private static extern uint GetExtendedTcpTable(

IntPtr pTcpTable, ref int dwOutBufLen, bool sort, int

ipVersion, int tblClass, int reserved);

[DllImport("")]

private static extern int SetTcpEntry(ref MIB_TCPROW pTcpRow);

[StructLayout(tial)]

private struct MIB_TCPROW

{

public TcpState dwState;

public int dwLocalAddr;

public int dwLocalPort;

public int dwRemoteAddr;

public int dwRemotePort;

}

[StructLayout(tial)]