MSDN声明
Socket.Shutdown
可以扔
SocketException
. 在我的客户机和服务器之间引入负载均衡器之后,最近我在生产中遇到了这种情况。但是,在没有负载均衡器的测试中,我不能复制它。你能?
一些背景知识-我有一个用c编写的服务器应用程序,它使用
TCP
与客户端通信的套接字。服务器的应用程序协议非常简单:接受连接、读取请求、发送响应、等待客户端关闭(读取预期为0字节)、关闭。
此代码已在生产中多年没有问题。然而,在多台服务器机器上引入负载均衡器之后,服务器进程中的一个由于未处理而崩溃。
插座异常
服务器调用时引发的
Socket.Shutdown
. 特定客户端在等待服务器响应时超时,并试图提前关闭连接。服务器上的异常消息是“远程主机强制关闭了现有连接”。客户端这样做并不罕见,但显然在负载平衡器之前,服务器在代码中的另一点引发此错误。尽管如此,这显然是一个服务器错误,修复是显而易见的-处理异常。
但是,使用测试客户机应用程序(也用c编写),我找不到会导致服务器在
套接字。关闭
. 看来,负载平衡器做了一些不寻常的
传输控制协议
包,但我仍然不喜欢使用它作为未能重现问题的借口。
我可以在debug中运行服务器和客户机代码,我让wireshark监视数据包。
在客户端,建立连接后,操作如下:
Socket.Send() // single call
Socket.Receive() // this one times out in our scenario
Socket.XXX() // various choices as described below
在服务器端,建立连接后,操作如下:
1) Socket.Receive()
2)
3) Socket.Write()
4) Socket.Receive()
5) Socket.Shutdown()
假设每个呼叫都有
try..catch(SocketException)
a)如果在步骤2中暂停服务器,等待客户端超时,并启动客户端停机使用
Socket.Shutdown(SocketShutDown.Send)
一个fin包被发送到服务器。当服务器恢复处理时,所有的调用都会成功(3到5),因为这是一个完全可接受的TCP流。
B)如果在步骤2中暂停服务器,等待客户端超时,并启动客户端停机使用
Socket.Shutdown(SocketShutDown.Both)
或
Socket.Close()
再次向服务器发送fin数据包。当服务器恢复时,处理步骤3成功,但它使客户端响应于不接收更多数据而发送RST包。如果这个RST在步骤4之前到达
Socket.Receive
投掷,第5步成功。如果它在步骤4之后到达,那么
套接字.接收
成功(返回0字节),但步骤5成功。
c)如果客户端有“不逗留”设置(使用0超时启用逗留),并且在处理期间暂停服务器,等待客户端超时,并启动客户端停机使用
socket.shutdown(socketshutdown.both)
或
套接字。关闭()
“rst”数据包立即发送到服务器。当服务器恢复处理时,步骤3和4将失败,但步骤5仍然成功。
我想最让我困惑的是
套接字。关闭
似乎忽略了我的测试客户端RST包,但显然我的负载均衡器能够发送一个不被忽略的RST包。我错过了什么?我还能试什么?