程序退出后TcpListener套接字仍然处于活动状态

12

我正在尝试在程序退出时停止TCP侦听器。我不关心当前在套接字上活动的任何数据或任何活动客户端套接字。

套接字清理代码基本上是:

try
{
    myServer.Server.Shutdown(SocketShutdown.Both)
}
catch (Exception ex)
{
     LogException(ex)
}
myServer.Server.Close(0)
myServer.Stop()

我的服务器是一个TCPListener。

在某些情况下,关闭操作将抛出异常。

System.Net.Sockets.SocketException: 因为套接字未连接且未提供地址(在使用sendto调用发送数据报套接字时),因此禁止请求发送或接收数据 at System.Net.Sockets.Socket.Shutdown(SocketShutdown how)

编辑 2010年5月14日

经过进一步调查,发现即使会引发异常,套接字也可以正确关闭。

有时,甚至在应用程序退出后,netstat仍然显示套接字处于LISTENING状态。

客户端套接字是独立清理的。

你有什么建议可以帮助我让这个套接字关闭吗?


C#的监听套接字在我看来表现得相当奇怪。或许这只是Windows的问题。我有一个类似的(尚未解决)问题,也许那里的答案能帮到你,尽管我们的问题有些不同:https://dev59.com/UE3Sa4cB1Zd3GeqPxsDq - IVlad
问题非常相似。套接字仍处于LISTENING状态,未能转换为TIME_WAIT。重新启动应用程序会导致“每个套接字地址只能使用一次…”的错误。 - lnical
是的,该应用程序是多线程的。线程被设置为IsBackground = true,当主GUI线程结束时应该结束。看起来线程应该被关闭并停止服务器。它确实会在大多数情况下这样做,但当异常发生并被处理时就不会这样做。 - lnical
我的服务器在代码后面被设置为null。 - lnical
这里也有完全相同的问题,你找到解决办法了吗? - iddqd
显示剩余3条评论
4个回答

3

使用finally块,在出现异常的情况下调用Close():

try
{
    myServer.Server.Shutdown(SocketShutdown.Both);
}
catch (Exception ex)
{
    LogException(ex);
}
finally
{
    myServer.Server.Close(0);
    myServer.Stop();
}

我也很好奇是否需要操作底层套接字,因为你没有提到某些规范?在大多数情况下,TCPListener/Client的设计使您不必担心这些通信机制。

此外,如果这并没有帮助,那么SocketException返回的是什么错误代码?


由于程序退出后,这个开放的套接字仍然保持在监听状态中,因此添加了Socket Shutdown。在某些情况下(不是全部,并且不能完全重现),套接字仍然保持打开状态。在生产代码中,关闭和停止命令被包装在另一个try-catch-finally结构中,并带有更多的日志记录。这些命令没有抛出异常。根据错误代码,我相信错误代码是WSAENOTCONN 10057。经过进一步研究,有时会抛出关闭错误并且套接字正常关闭。我将编辑主要问题以添加该信息。谢谢。 - lnical
考虑可能的解决方案,我在想客户端是否是问题的原因。套接字的Dispose对应于客户端的关闭。因此,套接字的孤立状态可能是客户端没有正确断开连接的症状。客户端的连接和断开是否以相对原子的方式设计?我认为跟踪可以帮助揭示这个问题。如果您还没有设置,请查看此链接:http://2.ly/3K2。我会写说明,但我没有足够的字符了。需要一些筛选,但是跟踪应该可以揭示通信中断发生的位置。 - Sorax

1

在关闭之前尝试调用Stop...


0

当您的应用程序退出后,套接字不能处于监听状态。但是,它可能处于等待状态,这是完全正常的。


应用程序不再显示在任务管理器中。与套接字相关联的 PID 与任务管理器中的任何进程无关。连接状态根据 netstat 在应用程序退出三小时后仍处于 LISTENING 状态。 - lnical
1
你能用 Process ExplorerTCPView 进行验证吗? TCPView 应该会得到与 netstat 相同的结果,但 Process Explorer 比任务管理器更详尽。 - Stephen Cleary
嗯...我能想到的唯一可能是某些东西正在干扰内核进程结构。很多病毒都这样做。也有可能是网络驱动程序的缺陷。我建议至少检查更新。这绝对不是正确的行为 - 我是指操作系统/驱动程序部分。 :) - Stephen Cleary
错误发生在不同位置的多个设备上。我不确定这是否是操作系统级别的问题。每台机器的准备工作都类似于其他机器。 - lnical
对我来说,这仍然不太对。当进程终止时,关闭句柄是操作系统的责任;在连接套接字的情况下,它可能会进入等待状态一段时间,然后才实际关闭,但监听套接字应立即关闭。异常、垃圾回收、处理和所有这些都无关紧要——如果您的进程实际退出,那么清理工作就是操作系统的工作... - Stephen Cleary
显示剩余2条评论

0

有一个类似的问题: - TcpListener等待客户端连接 - 关闭时使用Dispose

我也遇到了同样的问题(win7,win2k)。

对我有效的解决方案是在处理监听器时关闭与客户端的每个连接。如果程序在仍有活动连接的情况下退出,则这些连接可能会在程序关闭后仍然存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接