嘿...我使用I/O完成端口和Winsock创建了一个小型测试服务器。我可以成功地将插座手柄与完成端口联系起来。但是我不知道如何将用户定义的数据结构传递到Wroker线程...

到目前为止,我已经尝试的是通过用户结构 (ULONG_PTR)&structure as 协会通话中的完成密钥 CreateIoCompletionPort()但这无效。

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

因此,我的问题是:如何使用wsarecv(),getQueuedCompletionStatus()和完成数据包或重叠 - 解决方案将数据传递到工作线程?

编辑:我如何成功传输“每连接数据”?...似乎我有这样做的艺术(就像上面两个链接中的解释)错误。

这里是我的代码:(是的,它的丑陋和唯一的测试代码)

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);
}
有帮助吗?

解决方案

您可以通过 PastqueCompletionStatus.

I/O完成数据包将满足对GetQueuedCompletionStatus函数的出色呼叫。该函数以三个值传递的三个值返回,作为呼叫呼叫的第二,第三和第四参数。该系统不使用或验证这些值。特别是,lpoverlaped参数不必指向重叠的结构。

其他提示

如果您像这样通过结构,应该可以正常工作:

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的经常滥用功能之一是它们不复制重叠的结构,它们只是使用提供的一个 - 因此,从GetQuequeudCompletionStatus点返回的重叠结构点到了最初提供的结构。所以:

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

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

请注意,再次,在原始样本中,您弄错了铸造。 (重叠*)菲尔珀(Phelper)将指针传递到了辅助架结构的开始,但重叠的部分被宣布为最后一次。我更改了它以传递实际重叠部分的地址,这意味着代码不带铸件编译,这使我们能够 知道 我们正在做正确的事情。我还将重叠的结构移至结构的第一个成员。

在另一侧捕获数据:

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

在这方面,重叠的结构是辅助结构的第一个成员,这一点尤其重要,因为这使得从API给我们的重叠*和我们实际想要的助手*的助手*中轻松降回。

我使用标准套接字例程(套接字,关闭,绑定,接受,连接...)来创建/破坏和读取I/O,因为它们允许使用重叠的结构。

插座接受或连接后,您应将其与IT服务的会话上下文相关联。然后,将套接字关联到IOCP,(在第三个参数中)向其提供了对会话上下文的引用。 IOCP不知道该参考是什么,也不关心这一点。该引用是供您使用的,因此当您通过GetQueuedCompletionStatus获得IOC时,参数3指向的变量将被参考填充,以便您立即找到与套接字事件相关的上下文,并可以开始为事件提供服务。我通常使用索引结构,其中包含(除其他事项)插座声明,重叠结构以及其他特定于会话的数据。参数i传递到参数3中创建的iococteptionport将是包含插座的结构成员的索引。

您需要检查GetQueuedCompletionStatus是否返回完成或超时。有了超时,您可以通过索引结构进行操作,例如(例如),如果其中一个已经计时或其他东西并采取适当的房屋保管措施。

还需要检查重叠的结构,以查看I/O正确完成。

服务IOCP的功能应为一个单独的多线程实体。使用与系统中有内核相同数量的线程,或者至少不超过它,因为它浪费了系统资源(您没有比系统中的内核数量更多的资源来维修事件,对吗? 。

IOCP确实是所有世界中最好的(太好了),任何人说“每个插座”或“在一个函数中的多个插座列表上等待”的人都不知道他们在说什么。前者强调您的调度程序,后者进行了投票,投票总是极为浪费。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top