如何在不关闭服务器套接字的情况下在C++客户端的主循环中接收数据?

How do I receive data in a C++ client's main loop without closing the server socket?

本文关键字:循环 数据 客户端 情况下 服务器 套接字 C++      更新时间:2023-10-16

我正在阅读这个winsock示例。

我正在尝试概念化如何创建一个具有到C#.NET服务器的持久TCP/IP连接的C++客户端程序。

我看到的问题是,为了让C++客户端离开接收循环,服务器必须关闭与客户端的套接字连接。

在我的情况下,服务器每隔几秒钟就会向客户端发送一次。我需要能够从服务器接收一个数据包,并重新启动主程序循环,以便客户端能够执行其其余功能。

如果这个接收代码在C++客户端的主循环中,那么如果服务器从未关闭与客户端的连接,客户端将永远不会停止接收:

// Receive until the peer closes the connection
do {
    iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
    if ( iResult > 0 )
        printf("Bytes received: %dn", iResult);
    else if ( iResult == 0 )
        printf("Connection closedn");
    else
        printf("recv failed with error: %dn", WSAGetLastError());
} while( iResult > 0 );

您选择使用的示例程序设计用于发送单个请求和接收单个响应。它使用连接的状态来指示请求的结束和响应的结束。

您可能希望使用不同的示例程序。在谷歌上搜索"winsock聊天示例"。

另一方面,要按照您的要求修改此程序,您可以将do-while循环替换为:

// Assume that the OP's protocol sends 100-byte packets. 
// Each while iteration attempts to receive one such packet.
// The while exits when the other side closes its connection.
while(1) {
    // Receive 100-byte packet 
    int receivedBytes;
    for(receivedBytes = 0; receivedBytes < 100; ) {
        int iResult = recv(ConnectSocket,
                           recvbuf+receivedBytes,
                           recvbuflen-receivedBytes, 0);
        if ( iResult > 0 ) {
            receivedBytes += iResult;
            printf("Bytes received: %dn", iResult);
        } else if ( iResult == 0 ) {
            printf("Connection closedn");
            break;
        } else {
            printf("recv failed with error: %dn", WSAGetLastError());
            break;
        }
    }
    if(receivedBytes == 100) {
        // ... process packet here
    } else {
        break;
    }
}

这里的问题是您无法知道recv()将在什么时候返回。有五种解决方法:

  1. 使插座不堵塞。(不推荐)
  2. 使用select()并超时
  3. 使用异步套接字。这可能是最快的方法,但更复杂
  4. 使用螺纹
  5. BSD kqueue