c++ - 如何使用 IOCP 将用户定义的数据传递给工作线程?

标签 c++ iocp user-defined-types worker-thread

嘿...我使用 I/O 完成端口和 Winsock 创建了一个小型测试服务器。 我可以成功连接并将套接字句柄与完成端口关联。 但我不知道如何将用户定义的数据结构传递到工作线程中......

到目前为止我所尝试的是将用户结构传递为 (ULONG_PTR)&structure as CreateIoCompletionPort() 关联调用中的完成键 但这并没有奏效。

现在我尝试定义自己的重叠结构并使用 CONTAINING_RECORD() ,如此处所述 http://msdn.microsoft.com/en-us/magazine/cc302334.aspxhttp://msdn.microsoft.com/en-us/magazine/bb985148.aspx 。 但这也行不通。 (我得到 pHelper 内容的奇怪值)

所以我的问题是:如何使用 WSARecv()、GetQueuedCompletionStatus() 和完成数据包或 OVERLAPPED-strucutre 将数据传递到工作线程?

编辑:我如何成功传输“每个连接数据”?...看来我的艺术(如上面两个链接中所解释的)错误。

这是我的代码:(是的,它很丑陋,而且是唯一的测试代码)

struct helper
    {
        SOCKET m_sock;
        unsigned int m_key;
        OVERLAPPED over;
    };


///////

SOCKET newSock = INVALID_SOCKET;
    WSABUF wsabuffer;
    char cbuf[250];
    wsabuffer.buf = cbuf;
    wsabuffer.len = 250;
    DWORD flags, bytesrecvd;


    while(true)
    {
        newSock = accept(AcceptorSock, NULL, NULL);
        if(newSock == INVALID_SOCKET)
            ErrorAbort("could not accept a connection");

        //associate socket with the CP
        if(CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, 3,0) != hCompletionPort)
            ErrorAbort("Wrong port associated with the connection");
        else
            cout << "New Connection made and associated\n";

        helper* pHelper = new helper;
        pHelper->m_key = 3;
        pHelper->m_sock = newSock;
        memset(&(pHelper->over), 0, sizeof(OVERLAPPED));
        flags = 0;
        bytesrecvd = 0;

        if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, (OVERLAPPED*)pHelper, NULL) != 0)
        {
            if(WSAGetLastError() != WSA_IO_PENDING)
                ErrorAbort("WSARecv didnt work");
        }
    }

    //Cleanup
    CloseHandle(hCompletionPort);
    cin.get();
    return 0;
}

DWORD WINAPI ThreadProc(HANDLE h)
{
    DWORD dwNumberOfBytes = 0;
    OVERLAPPED* pOver = nullptr;
    helper* pHelper = nullptr;
    WSABUF RecvBuf;
    char cBuffer[250];
    RecvBuf.buf = cBuffer;
    RecvBuf.len = 250;
    DWORD dwRecvBytes = 0;
    DWORD dwFlags = 0;
    ULONG_PTR Key = 0;

    GetQueuedCompletionStatus(h, &dwNumberOfBytes, &Key, &pOver, INFINITE);

    //Extract helper
    pHelper = (helper*)CONTAINING_RECORD(pOver, helper, over);


    cout << "Received Overlapped item" << endl;
    if(WSARecv(pHelper->m_sock, &RecvBuf, 1, &dwRecvBytes, &dwFlags, pOver, NULL) != 0)
        cout << "Could not receive data\n";
    else
        cout << "Data Received: " << RecvBuf.buf << endl;

    ExitThread(0);
}

最佳答案

如果您像这样传递结构,它应该可以正常工作:

helper* pHelper = new helper;
CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, (ULONG_PTR)pHelper,0);
...


helper* pHelper=NULL;
GetQueuedCompletionStatus(h, &dwNumberOfBytes, (PULONG_PTR)&pHelper, &pOver, INFINITE);

编辑以添加每个 IO 数据:

异步 ​​api 经常被滥用的功能之一是它们不复制 OVERLAPPED 结构,它们只是使用提供的结构 - 因此从 GetQueuedCompletionStatus 返回的重叠结构指向最初提供的结构。所以:

struct helper {
  OVERLAPPED m_over;
  SOCKET     m_socket;
  UINT       m_key;
};

if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, &pHelper->m_over, NULL) != 0)

请再次注意,在您的原始示例中,您的类型转换错误。 (OVERLAPPED*)pHelper 正在将指针传递给辅助结构的 START,但 OVERLAPPED 部分是最后声明的。我将其更改为传递实际重叠部分的地址,这意味着代码无需强制转换即可编译,这让我们知道我们正在做正确的事情。我还将重叠的结构移动为该结构的第一个成员。

捕获另一端的数据:

OVERLAPPED* pOver;
ULONG_PTR key;
if(GetQueuedCompletionStatus(h,&dw,&key,&pOver,INFINITE))
{
  // c cast
  helper* pConnData = (helper*)pOver;

在这一方面,特别重要的是重叠结构是辅助结构的第一个成员,因为这样可以轻松地从 api 提供的 OVERLAPPED* 以及我们实际想要的辅助* 中进行转换。

关于c++ - 如何使用 IOCP 将用户定义的数据传递给工作线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4344162/

相关文章:

c++ - 虚函数的继承

c++ - 如何知道一个完成数据包是用于 WSASend() 或 WSARecv() 还是 AcceptEx()?

c# - 我在哪里/如何找到 .net 类是否使用 IOCP?

postgresql - 如何在 postgresql 中显示用户的 udt 定义?

c++ - 如何在 Linux 上编译 Windows Visual C++ 代码

c++ - ppoll 中的信号未立即处理

.net - 如何从 WCF 服务返回用户定义的类型?

database - PL/SQL - 对嵌套自定义对象的集合进行排序

c++ - 可变参数函数和可变参数模板重载查找

windows - 线程数和处理器核心数有什么关系?