IOCP 服务器的非 IOCP 客户端发送/接收错误

Posted

技术标签:

【中文标题】IOCP 服务器的非 IOCP 客户端发送/接收错误【英文标题】:Non-IOCP client send/recv error with IOCP server 【发布时间】:2015-12-11 09:23:37 【问题描述】:

请理解我是 IOCP 新手,我的代码可能不是那么完美。

我尝试了很多这里的例子,但没有一个能帮助我。 我的实际问题在客户端,我不知道我是否正确连接到 IOCP 服务器,如果我正确发送数据并且 recv 给我 WSAerror 10038 ...

    WSADATA wsd;
    struct addrinfo *result = NULL, *ptr = NULL, hints;
    WSAOVERLAPPED RecvOverlapped;
    SOCKET ConnSocket = INVALID_SOCKET;
    WSABUF DataBuf;
    DWORD RecvBytes, Flags;
    CRITICAL_SECTION criti;
    char buffer[DATA_BUFSIZE];
    int err = 0;
    int rc;

    // Load Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsd);
    if (rc != 0) 
        return 1;
    

    // Make sure the hints struct is zeroed out
    SecureZeroMemory((PVOID)& hints, sizeof(struct addrinfo));

    // Initialize the hints to retrieve the server address for IPv4
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    rc = getaddrinfo(IP, Port, &hints, &result);
    if (rc != 0) 
        return 1;
    

    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) 
        if ((ConnSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) == INVALID_SOCKET)

            freeaddrinfo(result);
            return 1;
        

        rc = connect(ConnSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (rc == SOCKET_ERROR) 

            if (WSAECONNREFUSED == (err = WSAGetLastError())) 
                closesocket(ConnSocket);
                ConnSocket = INVALID_SOCKET;
                continue;
            

            freeaddrinfo(result);
            closesocket(ConnSocket);
            WSACleanup();
            return 1;
        
        break;
    
    if (ConnSocket == INVALID_SOCKET)  

        freeaddrinfo(result);
        return 1;
    

    int nZero = 0;

    // Make sure the RecvOverlapped struct is zeroed out
    SecureZeroMemory((PVOID)& RecvOverlapped, sizeof(WSAOVERLAPPED));

    // Create an event handle and setup an overlapped structure.
    RecvOverlapped.hEvent = WSACreateEvent();
    if (RecvOverlapped.hEvent == NULL) 

        freeaddrinfo(result);
        closesocket(ConnSocket);
        return 1;
    

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;

    // send data to server here?
    // removed the packets, it`s not supposed to be public

    // Call WSARecv until the peer closes the connection
    // or until an error occurs
    while (1) 

        Flags = 0;
        RecvBytes = 0;


        rc = WSARecv(ConnSocket, &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
        if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) 

            closesocket(ConnSocket);
            break;

        

        rc = WSAWaitForMultipleEvents(1, &RecvOverlapped.hEvent, TRUE, INFINITE, TRUE);
        if (rc == WSA_WAIT_FAILED)     

            break;
        

        rc = WSAGetOverlappedResult(ConnSocket, &RecvOverlapped, &RecvBytes, FALSE, &Flags);
        if (rc == FALSE) 

            break;
        


        // here I have a protocol where I read the received data

        WSAResetEvent(RecvOverlapped.hEvent);

        // If 0 bytes are received, the connection was closed
        if (RecvBytes == 0)
            break;
    

    WSACloseEvent(RecvOverlapped.hEvent);
    closesocket(ConnSocket);
    freeaddrinfo(result);

    WSACleanup();

我希望能够发送数据并接收来自 IOCP 的响应,但是如果我发送 3 个数据包,当我发送 3 个数据包时,我只会收到 2 个或有时甚至 1 个。 有人可以向我展示一个将数据连接并发送+接收数据到 IOCP 服务器的工作示例吗?

非常感谢!

【问题讨论】:

【参考方案1】:

您正在使用 TCP。 TCP 是 stream 协议,而不是数据报协议。你不能告诉它要发送什么数据包,它不能告诉你它收到了什么数据包(它甚至不知道,因为这是在 IP 层处理的)。就是这样不行。

这句话充满智慧:“TCP 是一种双向、面向连接的字节流协议,它提供可靠、有序的传递,但不保留应用程序消息边界。”将“TCP”输入您最喜欢的搜索引擎并进行研究,直到您准确理解该句子中每个单词的含义。除非您这样做,否则您永远不会编写可靠甚至正确的 TCP 代码。

服务器是否使用 IOCP 或其他一些内部架构对客户端没有影响。那是完全看不见的。

【讨论】:

以上是关于IOCP 服务器的非 IOCP 客户端发送/接收错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 IOCP 的 TCP/IP 服务器。接收缓冲区中的偶尔数据损坏

没有完成键的 IOCP 通知

将非 IOCP 客户端与 IOCP 服务器连接

当服务器基于 iocp 时,我是不是需要让客户端支持 iocp?

IOCP怎么正确关闭socket

并发程序设计6:IOCP