WSAEventSelect 模型
嘿,我正在使用 WSAEventSelect 来获取套接字的事件通知。到目前为止,一切都很酷并且工作得很好,但有一个问题。
客户端是.NET应用程序,服务器是用Winsock C++编写的。在 .NET 应用程序中,我使用 System.Net.Sockets.Socket 类来实现 TCP/IP。当我调用 Socket.Shutdown() 和 Socket.Close() 方法时,我在服务器中收到 FD_CLOSE 事件,我很确定该事件没问题。好的,当我检查传递给 WSAEnumNetworkEvents 的 WSANETWORKEVENTS 的 iErrorCode 时,问题发生了。我这样检查
if (listenerNetworkEvents.lNetworkEvents & FD_CLOSE)
{
if (listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
{
// it comes here
// which means there is an error
// and the ERROR I got is
// WSAECONNABORTED
printf("FD_CLOSE failed with error %d\n",
listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT]);
break;
}
closesocket(socketArray[Index]);
}
但它失败并出现 WSAECONNABORTED 错误。为什么会这样呢?
编辑:顺便说一句,我在同一台计算机上运行客户端和服务器,是因为这个吗?当我这样做时,我收到了 FD_CLOSE 事件:
server.Shutdown(SocketShutdown.Both); // in .NET C#, client code
Hey I'm using the WSAEventSelect for event notifications of sockets. So far everything is cool and working like a charm, but there is one problem.
The client is a .NET application and the server is written in Winsock C++. In the .NET application I'm using System.Net.Sockets.Socket class for TCP/IP. When I call the Socket.Shutdown() and Socket.Close() method, I receive the FD_CLOSE event in the server, which I'm pretty sure is fine. Okay the problem occurs when I check the iErrorCode of WSANETWORKEVENTS which I passed to WSAEnumNetworkEvents. I check it like this
if (listenerNetworkEvents.lNetworkEvents & FD_CLOSE)
{
if (listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
{
// it comes here
// which means there is an error
// and the ERROR I got is
// WSAECONNABORTED
printf("FD_CLOSE failed with error %d\n",
listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT]);
break;
}
closesocket(socketArray[Index]);
}
But it fails with the WSAECONNABORTED error. Why is that so?
EDIT: Btw, I'm running both the client and server on the same computer, is it because of that? And I received the FD_CLOSE event when I do this:
server.Shutdown(SocketShutdown.Both); // in .NET C#, client code
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我猜您是在调用 Shutdown() ,然后立即调用 Close() 。这将给出您所看到的症状,因为这是“猛然关闭连接”。 Shutdown() 确实会启动正常断开连接 (TCP FIN),但紧随其后的 Close() 会中止该连接,并向远程对等方发送 TCP RST 数据包。顺便说一句,您的 Shutdown(SocketShutdown.Both) 调用也会关闭连接。
正确的模式是:
调用 Shutdown(),并将方向参数设置为“write”,这意味着我们不会再向远程对等点发送任何数据。这会导致堆栈发送 TCP FIN 数据包。
返回等待 Winsock 事件。当远程对等点也完成写入时,它也会调用 Shutdown("write"),导致其堆栈向您的计算机发送 TCP FIN 数据包,并使您的应用程序获得 FD_CLOSE 事件。在等待期间,您的代码应该准备好继续从套接字读取数据,因为远程对等点可能仍在发送数据。
(请原谅上面的伪 C#。我不会讲 .NET,只会讲 C++。)
两个对等点都应使用相同的关闭模式:每个对等点何时完成写入,然后等待接收远程通知对等方在关闭其套接字之前已完成写入。
重要的是要认识到 TCP 是一种双向协议:每一方都可以独立于另一方发送和接收。关闭套接字以进行读取并不是一件好事。这就像与另一个人交谈,但只说而不愿意听。优雅的关闭协议说:“我现在已经说完了。我要等到你停止说话后再走开。”
I'm guessing you're calling Shutdown() and then Close() immediately afterward. That will give the symptom you're seeing, because this is "slamming the connection shut". Shutdown() does initiate a graceful disconnect (TCP FIN), but immediately following it with Close() aborts that, sending a TCP RST packet to the remote peer. Your Shutdown(SocketShutdown.Both) call slams the connection shut, too, by the way.
The correct pattern is:
Call Shutdown() with the direction parameter set to "write", meaning we won't be sending any more data to the remote peer. This causes the stack to send the TCP FIN packet.
Go back to waiting for Winsock events. When the remote peer is also done writing, it will call Shutdown("write"), too, causing its stack to send your machine a TCP FIN packet, and for your application to get an FD_CLOSE event. While waiting, your code should be prepared to continue reading from the socket, because the remote peer might still be sending data.
(Please excuse the pseudo-C# above. I don't speak .NET, only C++.)
Both peers are expected to use this same shutdown pattern: each tells the other when it's done writing, and then waits to receive notification that the remote peer is done writing before it closes its socket.
The important thing to realize is that TCP is a bidirectional protocol: each side can send and receive independently of the other. Closing the socket to reading is not a nice thing to do. It's like having a conversation with another person but only talking and being unwilling to listen. The graceful shutdown protocol says, "I'm done talking now. I'm going to wait until you stop talking before I walk away."