IO 完成端口和 WSASend

IO Completion Ports and WSASend

提前抱歉,但请解释一下如何将 IOCP 与 WSASend 结合使用 - 例如,向服务器发送一条简单的消息并从中接收响应。

我正在这样做:

  1. 创建完成端口
  2. 为完成端口创建线程
  3. 我创建了一个带有 Overlaped 标志的 WSASocket。
  4. 我使用 WSAConnect
  5. 与远程服务器建立连接
  6. 我把套接字绑定到完成端口。
  7. 我向服务器发送消息 - 通过调用 WSASend 函数。

像这样:

void My_func_for_Thread(HANDLE iocp)
{

    DWORD my_DWORD;
    PULONG_PTR   my_CompletionKey;

    WSAOVERLAPPED* my_WSAOVERLAPPED_1;


    int my_GetLastError;


    while (1)
    {

        BOOL my_BOOL_GetQueuedCompletionStatus = GetQueuedCompletionStatus(iocp, &my_DWORD, my_CompletionKey, &my_WSAOVERLAPPED_1, INFINITE);


        my_GetLastError = GetLastError();

   
            if (my_BOOL_GetQueuedCompletionStatus == FALSE)
            {
                std::cout << "GetQueuedCompletionStatus== FALSE" << std::endl;
            }

      }
}

int main()
    {
    
    //-------------------------------------------------------------------Create port IO-------------------------------------------------------------
    
        int Number_Threads = 4;  
    
        HANDLE My_handle_IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, Number_Threads);
    
    //------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    
    //-------------------------------------------------------------------Create thread for IOCP-------------------------------------------------------
    
        std::vector<HANDLE>my_vector_Thread;
    
    
        for (int i = 0; i < Number_Threads; i++)
        {
            my_vector_Thread.push_back(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&My_func_for_Thread, My_handle_IOCP, 0, 0));
        }
    
    
    //---------------------------------------------------------------------------------------------------------------------------------------------------
    
   
    
    //-------------------------------------------------------------------Initialization Winsock-----------------------------------------------------------
    
    WORD my_version_Winsock = MAKEWORD(2, 2); 
    
    WSADATA my_wsadata_struct; 
    
    int my_WSAStartup = WSAStartup(my_version_Winsock, &my_wsadata_struct);
    
    //------------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    
    //-------------------------------------------------------------------Create WSASocket-----------------------------------------------------------------
    
    SOCKET my_WSASocketA = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
    
    //--------------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    
    //-------------------------------------------------------------------
    
        std::string myString_IP = "XX.XXX.XX.XXX";
    
    //--------------------------------------------------------------------------
    
        sockaddr my_sockaddr;                 
    
        my_sockaddr = { 0 };                                            
        my_sockaddr.sa_family = 2;                                          // AF_INET.
        inet_pton(AF_INET, myString_IP.c_str(), &my_sockaddr.sa_data[2]);   
        my_sockaddr.sa_data[1] = 80;                                     //http port
    
        //--------------------------------------------------------------------------
    

    
        int status_WSAConnect = WSAConnect(my_WSASocketA, &my_sockaddr, sizeof(my_sockaddr), NULL, NULL, NULL, NULL);
    
    
    //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    
    
    //-------------------------------------------------------------------Bind socket and port--------------------------------------------------------
    
        My_handle_Create_IOCP = CreateIoCompletionPort((HANDLE)my_WSASocketA, My_handle_IOCP, NULL, 0);
    
    //-------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    
    
    //-------------------------------------------------------------------Send message to serever with WSASend-----------------------------------
    
             WSABUF my_WSABUF;
    
             std::string request_text_string = "GET / HTTP/1.1\r\nHost: government.ru\r\nConnection: keep-alive\r\n\r\n";
    
    
             my_WSABUF.buf = &request_text_string[0];
             my_WSABUF.len = request_text_string.size();
    
    
             WSAOVERLAPPED my_WSAOVERLAPPED;
             my_WSAOVERLAPPED = { 0 };
    
    
    
             int my_WSASend =  WSASend(my_WSASocketA, &my_WSABUF, 1, NULL, 0, &my_WSAOVERLAPPED, NULL);
    
    
                     if (my_WSASend == SOCKET_ERROR)
             {
                       std::cout << "WSASend == SOCKET_ERROR:" std::endl;
                     }
    
                      if (my_WSASend == 0)
             {
                       std::cout << "WSASend == 0: no error" std::endl;
                     }
    
    
    //-----------------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    
             Sleep(10000);
    
    
             //---------------------------------------------------------
             for (int i = 0; i < Number_Threads; i++)
             {
                 CloseHandle(my_vector_Thread[i]);
             }
             //---------------------------------------------------------
    
    }

但是,GetQueuedCompletionStatus 总是 return998 - 对内存位置的访问无效。 哪个内存是禁止访问的?我做错了什么?

您的代码有几个问题。

您的 My_func_for_Thread() 函数的签名不适合与 CreateThread() 一起使用。编译器没有抱怨,因为您正在使用类型转换来阻止编译器失败。

您正在将 未初始化的 指针传递给 GetQueuedCompletionStatus()lpCompletionKey 参数。它需要一个指向有效 ULONG_PTR 变量的指针才能写入。

WSAOVERLAPPED 需要在内存中保持活动状态,直到从 IOCP 队列中检索到其最终状态。但是您的线程休眠时间比 main() 长得多 运行。您应该动态分配 WSAOVERLAPPED,然后在收到其状态时释放它。

尝试更像这样的东西:

DWORD WINAPI My_func_for_Thread(LPVOID lpParameter)
{
    HANDLE iocp = (HANDLE) lpParameter;
    DWORD my_DWORD;
    ULONG_PTR  my_CompletionKey;
    WSAOVERLAPPED* my_WSAOVERLAPPED_1;
    DWORD my_GetLastError;

    while (TRUE)
    {
        BOOL my_BOOL_GetQueuedCompletionStatus = GetQueuedCompletionStatus(iocp, &my_DWORD, &my_CompletionKey, (LPOVERLAPPED*) &my_WSAOVERLAPPED_1, INFINITE);

        my_GetLastError = GetLastError();

        if (my_BOOL_GetQueuedCompletionStatus)
        {
            delete my_WSAOVERLAPPED_1;
        }
        else
        {
            std::cout << "GetQueuedCompletionStatus == FALSE" << std::endl;
        }
    }

    return 0;
}

int main()
{
    ...

    for (int i = 0; i < Number_Threads; i++)
    {
        HANDLE hThread = CreateThread(NULL, 0, &My_func_for_Thread, My_handle_IOCP, 0, NULL);
        if (hThread)
            my_vector_Thread.push_back(hThread);
    }

    ...

    std::string request_text_string = "GET / HTTP/1.1\r\nHost: government.ru\r\nConnection: keep-alive\r\n\r\n";

    WSABUF my_WSABUF;
    my_WSABUF.buf = &request_text_string[0];
    my_WSABUF.len = request_text_string.size();

    WSAOVERLAPPED *my_WSAOVERLAPPED = new WSAOVERLAPPED;
    *my_WSAOVERLAPPED = { 0 };

    int my_WSASend =  WSASend(my_WSASocketA, &my_WSABUF, 1, NULL, 0, my_WSAOVERLAPPED, NULL);

    // wait for request to finish...
    // wait for response to arrive...
    // close socket...
    // wait for threads to terminate...

    ...

    for (size_t i = 0; i < my_vector_Thread.size(); i++)
    {
        CloseHandle(my_vector_Thread[i]);
    }

    return 0;
}