Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何构造IOCP的工作线程逻辑_C++_Oop_Winsock2_Iocp - Fatal编程技术网

C++ 如何构造IOCP的工作线程逻辑

C++ 如何构造IOCP的工作线程逻辑,c++,oop,winsock2,iocp,C++,Oop,Winsock2,Iocp,我正在创建一个客户端程序,通过局域网与连接到我电脑的设备进行通信 我的程序和设备之间的典型通信如下: Program -> Device 1616000D 08 02 00 00 00 21 11 A1 00 01 22 08 00 // Sender sends data (a specific command to the device) to Receiver Program <- Device 16160002 80 00 // Receiver sends AC

我正在创建一个客户端程序,通过局域网与连接到我电脑的设备进行通信

我的程序和设备之间的典型通信如下:

Program -> Device   1616000D  08 02 00 00 00 21 11 A1 00 01 22 08 00 // Sender sends data (a specific command to the device) to Receiver
Program <- Device   16160002  80 00 // Receiver sends ACK to sender
Program <- Device   16160005  08 20 00 00 00 // Receiver sends command response to sender
Program -> Device   16160002  80 00 // Sender sends ACK to receiver
Program->Device 1616000D 08 02 00 00 21 11 A1 00 01 22 08 00//发送方向接收方发送数据(向设备发送特定命令)
程序m_重叠),sizeof(wsaooverlapped));
perpiodata->m_socket=m_socket.Get();
perpiodata->m_overlapped.hEvent=WSACreateEvent();
perpiodata->m_vecBuffer.assign(veccomanddata.begin(),veccomanddata.end());
periodata->m_wsaBuf.buf=(CHAR*)(&(periodata->m_vecBuffer[0]);
pPerIoData->m_wsaBuf.len=pPerIoData->m_vecBuffer.size();
perpiodata->m_dwFlags=0;
Perpiodata->m_dwNumberOfBytesSent=0;
periodata->m_dwNumberOfBytesToSend=periodata->m_wsaBuf.len;
pPerIoData->m_operationType=OP_TYPE\u SEND;
if(!m_socket.Send(perpiodata))
返回false;
返回true;
}
我的辅助线程例程如下所示:

bool TcpConnection::SendCommand(const Command& rCommand, const std::vector<BYTE>& rvecCommandOptions)
{
    std::vector<BYTE> vecCommandData;
    m_commandBuilder.BuildCommand(rCommand, rvecCommandOptions, vecCommandData);

    if (vecCommandData.empty())
        return false;

    PerIoData *pPerIoData = new PerIoData;
    if (!pPerIoData)
        return false;

    SecureZeroMemory(&(pPerIoData->m_overlapped), sizeof(WSAOVERLAPPED));

    pPerIoData->m_socket = m_socket.Get();
    pPerIoData->m_overlapped.hEvent = WSACreateEvent();
    pPerIoData->m_vecBuffer.assign(vecCommandData.begin(), vecCommandData.end());
    pPerIoData->m_wsaBuf.buf = (CHAR*)(&(pPerIoData->m_vecBuffer[0]));
    pPerIoData->m_wsaBuf.len = pPerIoData->m_vecBuffer.size();
    pPerIoData->m_dwFlags = 0;
    pPerIoData->m_dwNumberOfBytesSent = 0;
    pPerIoData->m_dwNumberOfBytesToSend = pPerIoData->m_wsaBuf.len;
    pPerIoData->m_operationType = OP_TYPE_SEND;

    if (!m_socket.Send(pPerIoData))
        return false;

    return true;
}
DWORD WINAPI TcpConnection::WorkerThread(LPVOID lpParameter)
{
    HANDLE hCompletionPort = (HANDLE)lpParameter;
    DWORD dwNumberOfBytesTransferred;
    ULONG ulCompletionKey;
    PerIoData *pPerIoData;

    DWORD dwNumberOfBytesReceived;
    DWORD dwNumberOfBytesSent;
    DWORD dwFlags;

    while (GetQueuedCompletionStatus(hCompletionPort, &dwNumberOfBytesTransferred, &ulCompletionKey, (LPOVERLAPPED*)&pPerIoData, INFINITE)) 
    {
        if (!pPerIoData)
            continue;

        if ((dwNumberOfBytesTransferred == 0) && ((pPerIoData->m_operationType  == OP_TYPE_SEND) || (pPerIoData->m_operationType  == OP_TYPE_RECEIVE)))
        {
            closesocket(pPerIoData->m_socket);
            delete pPerIoData;
            continue;
        }

        if (pPerIoData->m_operationType == OP_TYPE_SEND)
        {
            pPerIoData->m_dwNumberOfBytesSent += dwNumberOfBytesTransferred;
            if (pPerIoData->m_dwNumberOfBytesSent < pPerIoData->m_dwNumberOfBytesToSend)
            {
                pPerIoData->m_wsaBuf.buf = (CHAR*)(&(pPerIoData->m_vecBuffer[pPerIoData->m_dwNumberOfBytesSent]));
                pPerIoData->m_wsaBuf.len = (pPerIoData->m_dwNumberOfBytesToSend - pPerIoData->m_dwNumberOfBytesSent);

                if (WSASend(pPerIoData->m_socket, &(pPerIoData->m_wsaBuf), 1, &dwNumberOfBytesTransferred, 0, &(pPerIoData->m_overlapped), NULL) == 0)
                    continue;

                if (WSAGetLastError() == WSA_IO_PENDING)
                    continue;
            }
            else if (pPerIoData->m_dwNumberOfBytesSent == pPerIoData->m_dwNumberOfBytesToSend)
            {
                delete pPerIoData;
            }

            // Q1. Do I create a new instance of PerIoData here before calling WSARecv() or reuse pPerIoData?

            // QA. If I did do "PerIoData pPerIoData = new PerIoData" here, how do I handle if this momory allocation request has failed?  Should I simply "continue" or "return -1"?

            // QB. Or is this a wrong place to do this memory allocation to achive the typical communication between my program and the device?

            SecureZeroMemory(&(pPerIoData->m_overlapped), sizeof(WSAOVERLAPPED));

            pPerIoData->m_overlapped.hEvent = WSACreateEvent();
            pPerIoData->m_wsaBuf.buf = (CHAR*)(&(pPerIoData->m_vecBuffer[0]));
            pPerIoData->m_wsaBuf.len = pPerIoData->m_vecBuffer.size();
            pPerIoData->m_operationType = OP_TYPE_RECEIVE;

            if (WSARecv(pPerIoData->m_socket, &(pPerIoData->m_wsaBuf), 1, &dwNumberOfBytesReceived, &(pPerIoData->m_dwFlags), &(pPerIoData->m_overlapped), NULL) == 0)
                continue;

            if (WSAGetLastError() == WSA_IO_PENDING)
                continue;
        }
        else if (pPerIoData->m_operationType == OP_TYPE_RECEIVE)
        {
            if ((pPerIoData->m_vecBuffer[0] == 0x16) && (pPerIoData->m_vecBuffer[1] == 0x16))
            {
                // Q2. Do I need to do SecureZeroMemory(&(pPerIoData->m_overlapped), sizeof(WSAOVERLAPPED)); here?

                // Q3. Or do I new PerIoData?

                pPerIoData->m_wsaBuf.buf = (CHAR*)(&(pPerIoData->m_vecBuffer[0]));
                pPerIoData->m_wsaBuf.len = pPerIoData->m_vecBuffer.size();
                pPerIoData->m_operationType = OP_TYPE_RECEIVE;

                // QC. At this point two syn bytes (0x16) are received.  I now need to receive two more bytes of data (000D = 13 bytes) to find out the size of the actual command response data.
                // If I clear my m_vecBuffer here and try to resize its size to two, I get this debug assertion: "vector iterators incompatible" at runtime.  Do you know how I can fix this problem?

                if (WSARecv(pPerIoData->m_socket, &(pPerIoData->m_wsaBuf), 1, &dwNumberOfBytesReceived, &(pPerIoData->m_dwFlags), &(pPerIoData->m_overlapped), NULL) == 0)
                    continue;

                if (WSAGetLastError() == WSA_IO_PENDING)
                    continue;
            }

            // QD. I'm not sure how to structure this if clause for when m_operationType is OP_TYPE_RECEIVE.  I mean how do I distinguish one receive operation for getting two syn bytes from another for getting data size?
            // One way I can think of doing is to create more receive operation types such as OP_TYPE_RECEIVE_DATA_SIZE or OP_TYPE_RECEIVE_DATA?  So you can have something like below.
            // Is this how you would do it?
        }
        //else if (pPerIoData->m_operationType == OP_TYPE_RECEIVE_DATA_SIZE)
        //{
            // Call WSARecv() again to get command response data
        //}
    }

    return 0;
}
DWORD WINAPI TcpConnection::WorkerThread(LPVOID lpParameter)
{
HANDLE hCompletionPort=(HANDLE)lpParameter;
DWORD DWNUMBEROFBYTEST传输;
ULONG-ulCompletionKey;
周期数据*PerIoData;
接收到的DWORD DWNUMBEROFBYTES;
德沃德·德沃德比特森;
德沃德旗;
while(GetQueuedCompletionStatus(hCompletionPort,&DwNumberOfByTestTransfered,&ulCompletionKey,(LPOVERLAPPED*)和pPerIoData,INFINITE))
{
如果(!periodata)
继续;
如果((DWNumberOfByTestTransferred==0)和((pPerIoData->m_操作类型==OP_类型_发送)| |(pPerIoData->m_操作类型==OP_类型_接收)))
{
闭合插座(pPerIoData->m_插座);
删除伪数据;
继续;
}
如果(pPerIoData->m_操作类型==操作类型发送)
{
pPerIoData->m_dwNumberOfBytesSent+=DWNumberOfByTestTransferred;
如果(pPerIoData->m_dwNumberOfBytesSentm_DWNumberOfByTestsEnd)
{
periodata->m_wsaBuf.buf=(CHAR*)(&(periodata->m_vecBuffer[periodata->m_dwNumberOfBytesSent]);
periodata->m_wsaBuf.len=(periodata->m_dwNumberOfBytesToSend-periodata->m_dwNumberOfBytesSent);
如果(WSASend(periodata->m_socket,&(periodata->m_wsaBuf),1,&dwnumberofbytesttransfered,0,&(periodata->m_overlapped),NULL)==0)
继续;
if(WSAGetLastError()==WSA_IO_PENDING)
继续;
}
否则如果(pPerIoData->m_dwNumberOfBytesSent==pPerIoData->m_DWNumberOfByTestsEnd)
{
删除伪数据;
}
//Q1.在调用WSARecv()或重用Perpiodata之前,是否在此处创建PerIoData的新实例?
//如果我在这里做了“PerIoData-PerIoData=new PerIoData”,如果这个内存分配请求失败了,我该如何处理?我应该简单地“继续”还是“返回-1”?
//或者这是一个错误的地方做这种内存分配,以实现我的程序和设备之间的典型通信?
SecureZeroMemory(&(perpiodata->m_重叠),sizeof(wsaooverlapped));
perpiodata->m_overlapped.hEvent=WSACreateEvent();
periodata->m_wsaBuf.buf=(CHAR*)(&(periodata->m_vecBuffer[0]);
pPerIoData->m_wsaBuf.len=pPerIoData->m_vecBuffer.size();
PERPIODATA->m_operationType=OP_TYPE_RECEIVE;
如果(WSARecv(periodata->m_socket,&(periodata->m_wsaBuf),1,&dwnumberofbytes接收,&(periodata->m_dwFlags),&(periodata->m_重叠),NULL)==0)
继续;
if(WSAGetLastError()==WSA_IO_PENDING)
继续;
}
else if(pPerIoData->m_operationType==OP_TYPE_RECEIVE)
{
如果((pPerIoData->m_vecBuffer[0]==0x16)和&(pPerIoData->m_vecBuffer[1]==0x16))
{
//问题2.我是否需要在这里执行SecureZeroMemory(&(perpiodata->m_overlapped),sizeof(wsaooverlapped))?
//或者我需要新的周期数据?
periodata->m_wsaBuf.buf=(CHAR*)(&(periodata->m_vecBuffer[0]);
pPerIoData->m_wsaBuf.len=pPerIoData->m_vecBuffer.size();
PERPIODATA->m_operationType=OP_TYPE_RECEIVE;
//此时接收到两个syn字节(0x16)。我现在需要再接收两个字节的数据(000D=13字节),以确定实际命令响应数据的大小。
//如果我在这里清除m_vecBuffer并尝试将其大小调整为2,我会在运行时得到以下调试断言:“向量迭代器不兼容”。您知道如何解决此问题吗?
如果(WSARecv(periodata->m_socket,&(periodata->m_wsaBuf),1,&dwnumberofbytes接收,&(periodata->m_dwFlags),&(periodata->m_重叠),NULL)==0)
继续;
if(WSAGetLastError()==WSA_IO_PENDING)
继续;
}
//我不知道当m_operationType为OP_TYPE_RECEIVE时如何构造这个if子句。我的意思是如何区分一个获取两个syn字节的接收操作和另一个获取数据大小的接收操作?
//我可以考虑的一种方法是创建更多的接收操作类型,如OP_TYPE_receive_DATA_SIZE或OP_TYPE_receive_DATA?这样您就可以有如下内容。
//你会这样做吗?
}
//else if(pPerIoData->m_操作类型==操作类型\u接收数据\u大小)
//{
//再次调用WSARecv()以获取命令响应数据
//}
}
返回0;
}
请参见上面代码中的问题

非常感谢

  • 正如
    PerIoData
    类型的名称所指,每个不完整的I/O请求都需要一个数据结构。
    PerIoData
    结构应该从您启动异步I