程序退出后,TcpListener Socket 仍然处于活动状态

Posted

技术标签:

【中文标题】程序退出后,TcpListener Socket 仍然处于活动状态【英文标题】:TcpListener Socket still active after program exits 【发布时间】:2011-02-18 19:39:35 【问题描述】:

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

socket 清理代码本质上是:

try

    myServer.Server.Shutdown(SocketShutdown.Both)

catch (Exception ex)

     LogException(ex)

myServer.Server.Close(0)
myServer.Stop()

myServer 是一个 TCPListener

在某些情况下,Shutdown 会抛出异常

System.Net.Sockets.SocketException: 不允许发送或接收数据的请求,因为未连接套接字并且(当使用 sendto 调用在数据报套接字上发送时)未提供地址 在 System.Net.Sockets.Socket.Shutdown(SocketShutdown 如何)

编辑 2010 年 5 月 14 日

进一步排查,可以抛出异常,正确关闭socket。

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

我无法创建明确的复制场景,它发生在看似随机的时间。

客户端套接字被独立清理。

你有什么建议可以帮我把这个插座弄死吗?

【问题讨论】:

在我看来,C# 监听套接字的行为很奇怪。或者也许它只是窗户。我有一个类似(尚未解决)的问题,也许那里的答案会对你有所帮助,虽然我们的问题有点不同:***.com/questions/2821520/… 问题非常相似。 Socket 保持在 LISTENING 状态,不会变为 TIME_WAIT。重新启动应用程序会导致“每个套接字地址只能使用一次......”错误。 好吧,我只是在那儿愚蠢,现在我得到了解决方案。问题是,它在重新启动程序后对我有用,只是没有重新启动它。你在你的程序中使用线程吗? 是的,应用程序是多线程的。线程被设置为 IsBackground = true,它应该在主 GUI 线程结束时结束。看起来线程应该关闭并且服务器停止。确实如此 - 大多数时候,但不是在异常发生和处理时。 您是否尝试过在异常捕获上设置 myServer = null (使其无法访问并支持 GC)?我想你以后需要重新实例化它...... 【参考方案1】:

在发生异常时使用 finally 块调用 Close():

try

    myServer.Server.Shutdown(SocketShutdown.Both);

catch (Exception ex)

    LogException(ex);

finally

    myServer.Server.Close(0);
    myServer.Stop();

我也很好奇是否因为您未提及的某些规范而需要对底层套接字进行操作? TCPListener/Client 旨在让您在大多数情况下不必担心那些通信机制。

另外,如果这没有帮助,那么 SocketException 返回的 ErrorCode 是什么?

【讨论】:

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

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

【讨论】:

【参考方案3】:

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

【讨论】:

应用程序不再显示在任务管理器中。与套接字关联的 PID 与任务管理器中的任何进程都不相关。应用程序退出三小时后根据 netstat LISTENING 的连接状态。 我已经退出程序并且当前正在监听的套接字。如果您想了解更多信息,请告诉我。 您能使用Process Explorer 和TCPView 进行验证吗? TCPView 应该给出与 netstat 相同的结果,但 Process Explorer 比 Task Manager 更详尽。 TCPView 以更易于阅读的格式显示与 netstat 相同的信息。谢谢你提醒我。它显示 :3580 TCP PCNAME:19000 PCNAME:0 LISTENING。 Process Explorer 显示可执行文件未运行。 嗯...我能想到的唯一一件事就是弄乱了内核进程结构。很多病毒都是这样做的。也可能是网络驱动程序错误。我至少会检查更新。这绝对不是正确的行为——我的意思是,就操作系统/驱动程序而言。 :)【参考方案4】:

有类似的问题: - TcpListener 等待客户端连接 - 关闭处理

有同样的问题(win7、win2k)。

对我来说有效的解决方案(?到目前为止)是在处理侦听器时关闭与客户端的每个连接。似乎如果程序在仍然存在活动连接VS客户端时存在,则这些连接可能会在程序关闭后保留。

【讨论】:

以上是关于程序退出后,TcpListener Socket 仍然处于活动状态的主要内容,如果未能解决你的问题,请参考以下文章

Socket网络编程(C#)----TcpListener 与 TcpClient

.NET SSH 隧道 - “System.Net.Sockets.Socket”类型的对象无法转换为“System.Net.Sockets.TcpListener”类型的对象

C# TcpListener如何知道客户端已经断开连接

我无法连接以测试使用 TcpListener 启动的本地服务器

socket长连接,心跳包怎么实现

TCP Listener 和 Socket 的区别