IO完成端口初始读取和双向数据 我有以下简化的IO完成端口服务器C++代码: int main(..) { startCompletionPortThreadProc(); // Await client connection sockaddr_in clientAddress; int clientAddressSize = sizeof( clientAddress ); SOCKET acceptSocket = WSAAccept( serverSocket, (SOCKADDR*)&clientAddress, &clientAddressSize, NULL, NULL); // Connected CreateIoCompletionPort( (HANDLE)acceptSocket, completionPort, 0, 0 ); // Issue initial read read( acceptSocket ); } DWORD WINAPI completionPortThreadProc( LPVOID param ) { DWORD bytesTransferred = 0; ULONG_PTR completionKey = NULL; LPPER_IO_DATA perIoData = NULL; while( GetQueuedCompletionStatus( completionPort, &bytesTransferred, &completionKey, (LPOVERLAPPED*)&perIoData, INFINITE ) ) { if( WaitForSingleObject( exitEvent, 0 ) == WAIT_OBJECT_0 ) { break; } if( !perIoData ) continue; if( bytesTransferred == 0 ) { //TODO } switch( perIoData->operation ) { case OPERATION_READ: { // Bytes have been received if( bytesTransferred < perIoData->WSABuf.len ) { // Terminate string perIoData->WSABuf.buf[bytesTransferred] = '\0'; perIoData->WSABuf.buf[bytesTransferred+1] = '\0'; } // Add data to message build message += std::tstring( (TCHAR*)perIoData->WSABuf.buf ); // Perform next read perIoData->WSABuf.len = sizeof( perIoData->inOutBuffer ); perIoData->flags = 0; if( WSARecv( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesTransferred, &( perIoData->flags ), &( perIoData->overlapped ), NULL ) == 0 ) { // Part message continue; } if( WSAGetLastError() == WSA_IO_PENDING ) { // End of message //TODO: Process message here continue; } } } break; case OPERATION_WRITE: { perIoData->bytesSent += bytesTransferred; if( perIoData->bytesSent < perIoData->bytesToSend ) { perIoData->WSABuf.buf = (char*)&( perIoData->inOutBuffer[perIoData->bytesSent] ); perIoData->WSABuf.len = ( perIoData->bytesToSend - perIoData->bytesSent); } else { perIoData->WSABuf.buf = (char*)perIoData->inOutBuffer; perIoData->WSABuf.len = _tcslen( perIoData->inOutBuffer ) * sizeof( TCHAR ); perIoData->bytesSent = 0; perIoData->bytesToSend = perIoData->WSABuf.len; } if( perIoData->bytesToSend ) { if( WSASend( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesTransferred, 0, &( perIoData->overlapped ), NULL ) == 0 ) continue; if( WSAGetLastError() == WSA_IO_PENDING ) continue; } } break; } } return 0; } bool SocketServer::read( SOCKET socket, HANDLE completionPort ) { PER_IO_DATA* perIoData = new PER_IO_DATA; ZeroMemory( perIoData, sizeof( PER_IO_DATA ) ); perIoData->socket = socket; perIoData->operation = OPERATION_READ; perIoData->WSABuf.buf = (char*)perIoData->inOutBuffer; perIoData->WSABuf.len = sizeof( perIoData->inOutBuffer ); perIoData->overlapped.hEvent = WSACreateEvent(); DWORD bytesReceived = 0; if( WSARecv( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesReceived, &( perIoData->flags ), &( perIoData->overlapped ), NULL ) == SOCKET_ERROR ) { int gle = WSAGetLastError(); if( WSAGetLastError() != WSA_IO_PENDING ) { delete perIoData; return false; } } return true; } bool SocketServer::write( SOCKET socket, std::tstring& data ) { PER_IO_DATA* perIoData = new PER_IO_DATA; ZeroMemory( perIoData, sizeof( PER_IO_DATA ) ); perIoData->socket = socket; perIoData->operation = OPERATION_WRITE; perIoData->WSABuf.buf = (char*)data.c_str(); perIoData->WSABuf.len = _tcslen( data.c_str() ) * sizeof( TCHAR ); perIoData->bytesToSend = perIoData->WSABuf.len; perIoData->overlapped.hEvent = WSACreateEvent(); DWORD bytesSent = 0; if( WSASend( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesSent, 0, &( perIoData->overlapped ), NULL ) == SOCKET_ERROR ) { if( WSAGetLastError() != WSA_IO_PENDING ) { delete perIoData; return false; } } return true; } int main(…) { startCompletionPortThreadProc(); //等待客户端连接 客户地址中的sockaddr_; int clientAddress size=sizeof(clientAddress); SOCKET-acceptSocket=wsaaaccept(serverSocket,(SOCKADDR*)&clientAddress,&clientAddress-size,NULL,NULL); //连接的 CreateIoCompletionPort((句柄)acceptSocket,completionPort,0,0); //问题初读 读取(接受套接字); } DWORD WINAPI completionPortThreadProc(LPVOID参数) { DWORD ByTestTransferred=0; ULONG_PTR completionKey=NULL; LPPER_IO_数据周期数据=NULL; while(GetQueuedCompletionStatus(completionPort,&ByTestTransfered,&completionKey,(LPOVERLAPPED*)和PeriodData,INFINITE)) { if(WaitForSingleObject(ExiteEvent,0)=等待对象0) { 打破 } 如果(!perIoData) 继续; 如果(ByTestTransferred==0) { //待办事项 } 开关(周期数据->操作) { 案例操作内容如下: { //已收到个字节 如果(通过测试传输WSABuf.len) { //终止字符串 perIoData->WSABuf.buf[ByTestTransfered]='\0'; perIoData->WSABuf.buf[ByTestTransfered+1]='\0'; } //将数据添加到消息生成 message+=std::tstring((TCHAR*)perIoData->WSABuf.buf); //执行下一次读取 perIoData->WSABuf.len=sizeof(perIoData->inOutBuffer); 周期数据->标志=0; 如果(WSARecv(perIoData->socket,&(perIoData->WSABuf),1,&bytesttransfered,&(perIoData->flags),&(perIoData->overlapped),NULL)==0) { //部分消息 继续; } if(WSAGetLastError()==WSA_IO_PENDING) { //消息结束 //TODO:在此处处理消息 继续; } } } 打破 案例操作(u WRITE): { perIoData->bytesSent+=ByTestTransferred; if(perIoData->bytesSentbytesToSend) { perIoData->WSABuf.buf=(char*)和(perIoData->inOutBuffer[perIoData->bytesSent]); perIoData->WSABuf.len=(perIoData->bytesToSend-perIoData->bytesent); } 其他的 { perIoData->WSABuf.buf=(char*)perIoData->inOutBuffer; perIoData->WSABuf.len=\u tcslen(perIoData->inOutBuffer)*sizeof(TCHAR); 周期数据->字节数=0; perIoData->bytesToSend=perIoData->WSABuf.len; } if(周期数据->bytesToSend) { 如果(WSASend(perIoData->socket,&(perIoData->WSABuf),1,&bytesttransfered,0,&(perIoData->overlapped),NULL)==0) 继续; if(WSAGetLastError()==WSA_IO_PENDING) 继续; } } 打破 } } 返回0; } boolsocketserver::read(套接字、句柄完成端口) { 每IO_数据*周期数据=新的每IO_数据; 零内存(perIoData,sizeof(PER_IO_数据)); 周期数据->套接字=套接字; 周期数据->操作=操作\读取; perIoData->WSABuf.buf=(char*)perIoData->inOutBuffer; perIoData->WSABuf.len=sizeof(perIoData->inOutBuffer); perIoData->overlapped.hEvent=WSACreateEvent(); 接收到的DWORD字节=0; 如果(WSARecv(perIoData->socket,&(perIoData->WSABuf),1,&bytesReceived,&(perIoData->flags),&(perIoData->overlapped),NULL)=socket\u错误) { int gle=WSAGetLastError(); 如果(WSAGetLastError()!=WSA\u IO\u挂起) { 删除周期数据; 返回false; } } 返回true; } boolsocketserver::write(套接字、std::tstring和数据) { 每IO_数据*周期数据=新的每IO_数据; 零内存(perIoData,sizeof(PER_IO_数据)); 周期数据->套接字=套接字; 周期数据->操作=操作\写入; perIoData->WSABuf.buf=(char*)data.c_str(); perIoData->WSABuf.len=\u tcslen(data.c_str())*sizeof(TCHAR); perIoData->bytesToSend=perIoData->WSABuf.len; perIoData->overlapped.hEvent=WSACreateEvent(); DWORD bytesSent=0; 如果(WSASend(perIoData->socket,&(perIoData->WSABuf),1,&bytesSent,0,&(perIoData->overlapped),NULL)==socket\u错误) { 如果(WSAGetLastError()!=WSA\u IO\u挂起) { 删除周期数据; 返回false; } } 返回true; }

IO完成端口初始读取和双向数据 我有以下简化的IO完成端口服务器C++代码: int main(..) { startCompletionPortThreadProc(); // Await client connection sockaddr_in clientAddress; int clientAddressSize = sizeof( clientAddress ); SOCKET acceptSocket = WSAAccept( serverSocket, (SOCKADDR*)&clientAddress, &clientAddressSize, NULL, NULL); // Connected CreateIoCompletionPort( (HANDLE)acceptSocket, completionPort, 0, 0 ); // Issue initial read read( acceptSocket ); } DWORD WINAPI completionPortThreadProc( LPVOID param ) { DWORD bytesTransferred = 0; ULONG_PTR completionKey = NULL; LPPER_IO_DATA perIoData = NULL; while( GetQueuedCompletionStatus( completionPort, &bytesTransferred, &completionKey, (LPOVERLAPPED*)&perIoData, INFINITE ) ) { if( WaitForSingleObject( exitEvent, 0 ) == WAIT_OBJECT_0 ) { break; } if( !perIoData ) continue; if( bytesTransferred == 0 ) { //TODO } switch( perIoData->operation ) { case OPERATION_READ: { // Bytes have been received if( bytesTransferred < perIoData->WSABuf.len ) { // Terminate string perIoData->WSABuf.buf[bytesTransferred] = '\0'; perIoData->WSABuf.buf[bytesTransferred+1] = '\0'; } // Add data to message build message += std::tstring( (TCHAR*)perIoData->WSABuf.buf ); // Perform next read perIoData->WSABuf.len = sizeof( perIoData->inOutBuffer ); perIoData->flags = 0; if( WSARecv( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesTransferred, &( perIoData->flags ), &( perIoData->overlapped ), NULL ) == 0 ) { // Part message continue; } if( WSAGetLastError() == WSA_IO_PENDING ) { // End of message //TODO: Process message here continue; } } } break; case OPERATION_WRITE: { perIoData->bytesSent += bytesTransferred; if( perIoData->bytesSent < perIoData->bytesToSend ) { perIoData->WSABuf.buf = (char*)&( perIoData->inOutBuffer[perIoData->bytesSent] ); perIoData->WSABuf.len = ( perIoData->bytesToSend - perIoData->bytesSent); } else { perIoData->WSABuf.buf = (char*)perIoData->inOutBuffer; perIoData->WSABuf.len = _tcslen( perIoData->inOutBuffer ) * sizeof( TCHAR ); perIoData->bytesSent = 0; perIoData->bytesToSend = perIoData->WSABuf.len; } if( perIoData->bytesToSend ) { if( WSASend( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesTransferred, 0, &( perIoData->overlapped ), NULL ) == 0 ) continue; if( WSAGetLastError() == WSA_IO_PENDING ) continue; } } break; } } return 0; } bool SocketServer::read( SOCKET socket, HANDLE completionPort ) { PER_IO_DATA* perIoData = new PER_IO_DATA; ZeroMemory( perIoData, sizeof( PER_IO_DATA ) ); perIoData->socket = socket; perIoData->operation = OPERATION_READ; perIoData->WSABuf.buf = (char*)perIoData->inOutBuffer; perIoData->WSABuf.len = sizeof( perIoData->inOutBuffer ); perIoData->overlapped.hEvent = WSACreateEvent(); DWORD bytesReceived = 0; if( WSARecv( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesReceived, &( perIoData->flags ), &( perIoData->overlapped ), NULL ) == SOCKET_ERROR ) { int gle = WSAGetLastError(); if( WSAGetLastError() != WSA_IO_PENDING ) { delete perIoData; return false; } } return true; } bool SocketServer::write( SOCKET socket, std::tstring& data ) { PER_IO_DATA* perIoData = new PER_IO_DATA; ZeroMemory( perIoData, sizeof( PER_IO_DATA ) ); perIoData->socket = socket; perIoData->operation = OPERATION_WRITE; perIoData->WSABuf.buf = (char*)data.c_str(); perIoData->WSABuf.len = _tcslen( data.c_str() ) * sizeof( TCHAR ); perIoData->bytesToSend = perIoData->WSABuf.len; perIoData->overlapped.hEvent = WSACreateEvent(); DWORD bytesSent = 0; if( WSASend( perIoData->socket, &( perIoData->WSABuf ), 1, &bytesSent, 0, &( perIoData->overlapped ), NULL ) == SOCKET_ERROR ) { if( WSAGetLastError() != WSA_IO_PENDING ) { delete perIoData; return false; } } return true; } int main(…) { startCompletionPortThreadProc(); //等待客户端连接 客户地址中的sockaddr_; int clientAddress size=sizeof(clientAddress); SOCKET-acceptSocket=wsaaaccept(serverSocket,(SOCKADDR*)&clientAddress,&clientAddress-size,NULL,NULL); //连接的 CreateIoCompletionPort((句柄)acceptSocket,completionPort,0,0); //问题初读 读取(接受套接字); } DWORD WINAPI completionPortThreadProc(LPVOID参数) { DWORD ByTestTransferred=0; ULONG_PTR completionKey=NULL; LPPER_IO_数据周期数据=NULL; while(GetQueuedCompletionStatus(completionPort,&ByTestTransfered,&completionKey,(LPOVERLAPPED*)和PeriodData,INFINITE)) { if(WaitForSingleObject(ExiteEvent,0)=等待对象0) { 打破 } 如果(!perIoData) 继续; 如果(ByTestTransferred==0) { //待办事项 } 开关(周期数据->操作) { 案例操作内容如下: { //已收到个字节 如果(通过测试传输WSABuf.len) { //终止字符串 perIoData->WSABuf.buf[ByTestTransfered]='\0'; perIoData->WSABuf.buf[ByTestTransfered+1]='\0'; } //将数据添加到消息生成 message+=std::tstring((TCHAR*)perIoData->WSABuf.buf); //执行下一次读取 perIoData->WSABuf.len=sizeof(perIoData->inOutBuffer); 周期数据->标志=0; 如果(WSARecv(perIoData->socket,&(perIoData->WSABuf),1,&bytesttransfered,&(perIoData->flags),&(perIoData->overlapped),NULL)==0) { //部分消息 继续; } if(WSAGetLastError()==WSA_IO_PENDING) { //消息结束 //TODO:在此处处理消息 继续; } } } 打破 案例操作(u WRITE): { perIoData->bytesSent+=ByTestTransferred; if(perIoData->bytesSentbytesToSend) { perIoData->WSABuf.buf=(char*)和(perIoData->inOutBuffer[perIoData->bytesSent]); perIoData->WSABuf.len=(perIoData->bytesToSend-perIoData->bytesent); } 其他的 { perIoData->WSABuf.buf=(char*)perIoData->inOutBuffer; perIoData->WSABuf.len=\u tcslen(perIoData->inOutBuffer)*sizeof(TCHAR); 周期数据->字节数=0; perIoData->bytesToSend=perIoData->WSABuf.len; } if(周期数据->bytesToSend) { 如果(WSASend(perIoData->socket,&(perIoData->WSABuf),1,&bytesttransfered,0,&(perIoData->overlapped),NULL)==0) 继续; if(WSAGetLastError()==WSA_IO_PENDING) 继续; } } 打破 } } 返回0; } boolsocketserver::read(套接字、句柄完成端口) { 每IO_数据*周期数据=新的每IO_数据; 零内存(perIoData,sizeof(PER_IO_数据)); 周期数据->套接字=套接字; 周期数据->操作=操作\读取; perIoData->WSABuf.buf=(char*)perIoData->inOutBuffer; perIoData->WSABuf.len=sizeof(perIoData->inOutBuffer); perIoData->overlapped.hEvent=WSACreateEvent(); 接收到的DWORD字节=0; 如果(WSARecv(perIoData->socket,&(perIoData->WSABuf),1,&bytesReceived,&(perIoData->flags),&(perIoData->overlapped),NULL)=socket\u错误) { int gle=WSAGetLastError(); 如果(WSAGetLastError()!=WSA\u IO\u挂起) { 删除周期数据; 返回false; } } 返回true; } boolsocketserver::write(套接字、std::tstring和数据) { 每IO_数据*周期数据=新的每IO_数据; 零内存(perIoData,sizeof(PER_IO_数据)); 周期数据->套接字=套接字; 周期数据->操作=操作\写入; perIoData->WSABuf.buf=(char*)data.c_str(); perIoData->WSABuf.len=\u tcslen(data.c_str())*sizeof(TCHAR); perIoData->bytesToSend=perIoData->WSABuf.len; perIoData->overlapped.hEvent=WSACreateEvent(); DWORD bytesSent=0; 如果(WSASend(perIoData->socket,&(perIoData->WSABuf),1,&bytesSent,0,&(perIoData->overlapped),NULL)==socket\u错误) { 如果(WSAGetLastError()!=WSA\u IO\u挂起) { 删除周期数据; 返回false; } } 返回true; },c++,winsock2,iocp,C++,Winsock2,Iocp,1) 我遇到的第一个问题是首读 在客户端连接(accept)上,我发出一个read。由于客户端尚未发送任何数据,WSAGetLastError()是WSA_IO_挂起的,read方法返回 当客户端随后发送数据时,线程仍停留在GetQueuedCompletionStatus调用中(我假设需要另一个WSARecv调用?) 我应该一直循环读取方法直到数据到达吗?这似乎不合逻辑,我认为通过发出初始读取GetQueuedCompletionStatus将在数据到达时完成 2) 我需要在没有应答的情况下双

1) 我遇到的第一个问题是首读

在客户端连接(accept)上,我发出一个read。由于客户端尚未发送任何数据,WSAGetLastError()是WSA_IO_挂起的,read方法返回

当客户端随后发送数据时,线程仍停留在GetQueuedCompletionStatus调用中(我假设需要另一个WSARecv调用?)

我应该一直循环读取方法直到数据到达吗?这似乎不合逻辑,我认为通过发出初始读取GetQueuedCompletionStatus将在数据到达时完成

2) 我需要在没有应答的情况下双向读取和写入数据。因此,我还使用IOCP线程创建了一个客户端。是否可以使用完成端口执行此操作,或者读取后必须执行写入操作

对不起,这是一个基本的问题
DWORD WINAPI completionPortThreadProc( LPVOID param )
{
    DWORD bytesTransferred = 0;
    ULONG_PTR completionKey = NULL;
    LPPER_IO_DATA perIoData = NULL;

    do
    {
        if( GetQueuedCompletionStatus( completionPort, &bytesTransferred, &completionKey, (LPOVERLAPPED*)&perIoData, INFINITE ) )
        {
            // I/O success, handle perIoData based on completionKey as needed...
        }
        else if( perIoData )
        {
            // I/O failed, handle perIoData based on completionKey as needed...
        }
        else
        {
            // GetQueuedCompletionStatus() failure...
            break;
        }    
    }
    while( WaitForSingleObject( exitEvent, 0 ) == WAIT_TIMEOUT );

    return 0;
}
DWORD WINAPI completionPortThreadProc( LPVOID param )
{
    DWORD bytesTransferred = 0;
    ULONG_PTR completionKey = NULL;
    LPPER_IO_DATA perIoData = NULL;

    do
    {
        if( GetQueuedCompletionStatus( completionPort, &bytesTransferred, &completionKey, (LPOVERLAPPED*)&perIoData, INFINITE ) )
        {
            if( completionKey == MyTerminateKey )
                break;

            if( completionKey == MySocketIOKey )
            {
                // I/O success, handle perIoData as needed...
            }
        }
        else if( perIoData )
        {
            // I/O failed, handle perIoData based on completionKey as needed...
        }
        else
        {
            // GetQueuedCompletionStatus() failure...
            break;
        }    
    }
    while( true );

    return 0;
}
CreateIoCompletionPort( (HANDLE)acceptSocket, completionPort, MySocketIOKey, 0 );
PostQueuedCompletionStatus( completionPort, 0, MyTerminateKey, NULL );