TCP套接字服务器偶尔会建立CLOSE_WAIT,直到无法操作

时间:2009-03-24 23:20:05

标签: c# performance sockets crash wireshark

希望有人可以帮助我们,因为我们已经达到调查的目的!

我们有一个用C#编写的简单异步套接字服务器,它接受来自ASP.NET Web应用程序的连接,发送消息,执行一些处理(通常是针对数据库而不是其他系统),然后发回一个响应给客户。客户负责关闭连接。

我们遇到的问题是,如果系统长时间处于高负荷状态(通常是几天),CLOSE_WAIT套接字会在服务器框(netstat -a)上建立到进程不接受的程度进一步的联系。那时我们必须反弹这个过程然后再次运行。

我们尝试运行ASP.NET应用程序的一些负载测试来尝试复制问题(因为无法从代码中推断出某些问题)。我们认为我们已经管理了这个并最终得到了一个问题的WireShark packet trace,它在套接字服务器的日志中表现为SocketException:

  

System.Net.Sockets.SocketException:远程主机强行关闭现有连接   at System.Net.Sockets.Socket.BeginSend(Byte [] buffer,Int32 offset,Int32 size,SocketFlags socketFlags,AsyncCallback callback,Object state)

我试图将数据包跟踪中的问题重新发送为直接与套接字服务器通信的单线程进程(使用与ASP.NET应用程序相同的代码),但我无法做到。

有没有人对接下来的事情有任何建议,检查或明显我们可能做错了什么?

6 个答案:

答案 0 :(得分:5)

如果您的服务器正在累积CLOSE_WAIT套接字,则在连接完成时它不会关闭其套接字。如果您查看Chris发布的评论中的状态图,您会看到CLOSE_WAIT在套接字关闭且LAST_ACK已发送后转换为FIN

你说由于异步性质,确定在哪里这样做很复杂吗?这应该不是问题,如果来自recv的回调返回0字节,则应该关闭套接字(假设您的客户端关闭其连接端后没有其他任何操作)。如果您确实需要担心继续发送,请在此处执行关机(recv)并记下您的客户已关闭,一旦您完成发送关机(发送)和关闭。

你可能在read的回调中发出一个新的读数,返回0表示客户端已经关闭,这可能会导致你出现问题?

答案 1 :(得分:5)

查看图表

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

您的客户端通过调用close()来关闭连接,后者将FIN发送到服务器套接字,服务器套接字确认FIN并且其状态现在已更改为CLOSE_WAIT,并保持该状态,除非服务器发出close()调用插座。

您的服务器程序需要检测客户端是否已中止连接,然后立即关闭()以释放端口。怎么样?请参阅read()。在读取文件结尾(意味着收到FIN)时,返回零。

答案 2 :(得分:3)

  

客户负责关闭连接。

客户端和服务器都必须关闭并关闭套接字。客户端没有完成关闭(不太可能 - 因为它有终结器运行)或服务器没有关闭套接字(可能)。

using (Socket s = new Socket(/* */)) {
  /* Do stuff */
  s.Shutdown(SocketShutdown.Both);
  s.Close();
}

答案 3 :(得分:0)

您不应该只负责关闭TCP套接字直到客户端。如果客户端进程/计算机崩溃会发生什么?

理想情况下,您应该有一个超时,这样如果在一定时间后连接的套接字上没有收到任何流量,那么服务器就会关闭它。

答案 4 :(得分:0)

无论客户端完成套接字上的所有操作后发生了什么,并且不需要对套接字执行任何更多读取操作,客户端都应发出close命令。

发出close命令,只是告诉监听器(服务器)需要关闭连接。

简单来说,当服务器再次以异步模式发出读命令(listener.read()或listener.beginread(...))时,read将返回0字节读取,这本身就表示套接字需要被监听器关闭,因为客户端已停止套接字上的任何其他操作。

答案 5 :(得分:-2)

CLOSE_WAIT用于在套接字关闭后暂停一段时间,以防止重新使用相同的套接字号并从旧连接接收数据包。如果你真的很快打开和关闭一个huuuuge插座,这只会让你感到悲伤。

编辑 - 它应该是TIME_WAIT,而不是上面的CLOSE_WAIT。