1

嘿,我正在使用 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
4

1 回答 1

2

我猜你是在调用 Shutdown() ,然后是 Close() 。这将给出您所看到的症状,因为这是“关闭连接”。Shutdown() 确实启动了正常断开连接(TCP FIN),但紧随其后的 Close() 中止了该操作,向远程对等方发送 TCP RST 数据包。顺便说一句,您的 Shutdown(SocketShutdown.Both) 调用也会关闭连接。

正确的模式是:

  1. 调用 Shutdown() 并将方向参数设置为“write”,这意味着我们不会再向远程对等方发送任何数据。这会导致堆栈发送 TCP FIN 数据包。

  2. 返回等待 Winsock 事件。当远程对等方也完成写入时,它也会调用 Shutdown("write"),导致其堆栈向您的机器发送 TCP FIN 数据包,并让您的应用程序获得 FD_CLOSE 事件。在等待期间,您的代码应该准备好继续从套接字读取,因为远程对等方可能仍在发送数据。

(请原谅上面的伪 C#。我不会说 .NET,只会说 C++。)

两个对等点都应该使用相同的关闭模式:当它完成写入时,每个都会告诉对方,然后在关闭其套接字之前等待接收远程对等点完成写入的通知。

需要意识到的重要一点是 TCP 是一个双向协议:每一方都可以相互独立地发送和接收。关闭套接字以阅读并不是一件好事。这就像和另一个人交谈,但只是说话而不愿意听。优雅的关机协议说,“我现在说完了。我要等到你停止说话,然后我才走开。”

于 2009-08-25T17:11:09.210 回答