IOCP完整例子

来源:互联网 发布:割平面法求解凸优化 编辑:程序博客网 时间:2024/05/16 23:52

本文是我在学习IOCP的时候,第一次写一个完整的例子出来,当然了,参考了CSDN上一些朋友的博客,大部分都是按照他们的思路写的,毕竟我是初学者,参考现成的学起来比较快。当然了,真正用到项目中的IOCP肯定不止这么简单的,还有内存池,环形缓冲区,socket连接池等高端内容,后面我会参考一些例子,写出一个完整的给大家看。

/************************************************************************FileName:iocp.hAuthor:eliteYanghttp://www.cppfans.org************************************************************************/#ifndef __IOCP_H__#define __IOCP_H__#include#include #define DefaultPort 20000#define DataBuffSize 8 * 1024typedef struct{OVERLAPPED overlapped;WSABUF databuff;CHAR buffer[ DataBuffSize ];DWORD bytesSend;DWORD bytesRecv;}PER_IO_OPERATEION_DATA, *LPPER_IO_OPERATION_DATA;typedef struct{SOCKET socket;}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;#endif前面讲过IOCP里面一个很重要的东西就是IO重叠了,所以结构体里有一个OVERLAPPED结构。/************************************************************************FileName:iocp.cppAuthor:eliteYanghttp://www.cppfans.org************************************************************************/#include "iocp.h"#include using namespace std;#pragma comment( lib, "Ws2_32.lib" )DWORD WINAPI ServerWorkThread( LPVOID CompletionPortID );void main(){SOCKET acceptSocket;HANDLE completionPort;LPPER_HANDLE_DATA pHandleData;LPPER_IO_OPERATION_DATA pIoData;DWORD recvBytes;DWORD flags;WSADATA wsaData;DWORD ret;if ( ret = WSAStartup( 0x0202, &wsaData ) != 0 ){std::cout << "WSAStartup failed. Error:" << ret << std::endl;return;}completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );if ( completionPort == NULL ){std::cout << "CreateIoCompletionPort failed. Error:" << GetLastError() << std::endl;return;}SYSTEM_INFO mySysInfo;GetSystemInfo( &mySysInfo );// 创建 2 * CPU核数 + 1 个线程DWORD threadID;for ( DWORD i = 0; i < ( mySysInfo.dwNumberOfProcessors * 2 + 1 ); ++i ){HANDLE threadHandle;threadHandle = CreateThread( NULL, 0, ServerWorkThread, completionPort, 0, &threadID );if ( threadHandle == NULL ){std::cout << "CreateThread failed. Error:" << GetLastError() << std::endl;return;}CloseHandle( threadHandle );}// 启动一个监听socketSOCKET listenSocket = WSASocket( AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED );if ( listenSocket == INVALID_SOCKET ){std::cout << " WSASocket( listenSocket ) failed. Error:" << GetLastError() << std::endl;return;}SOCKADDR_IN internetAddr;internetAddr.sin_family = AF_INET;internetAddr.sin_addr.s_addr = htonl( INADDR_ANY );internetAddr.sin_port = htons( DefaultPort );// 绑定监听端口if ( bind( listenSocket, (PSOCKADDR)&internetAddr, sizeof( internetAddr ) ) == SOCKET_ERROR ){std::cout << "Bind failed. Error:" << GetLastError() << std::endl;return;}if ( listen( listenSocket, 5 ) ==  SOCKET_ERROR ){std::cout << "listen failed. Error:" << GetLastError() << std::endl;return;}// 开始死循环,处理数据while ( 1 ){acceptSocket = WSAAccept( listenSocket, NULL, NULL, NULL, 0 );if ( acceptSocket == SOCKET_ERROR ){std::cout << "WSAAccept failed. Error:" << GetLastError() << std::endl;return;}pHandleData = (LPPER_HANDLE_DATA)GlobalAlloc( GPTR, sizeof( PER_HANDLE_DATA ) );if ( pHandleData = NULL ){std::cout << "GlobalAlloc( HandleData ) failed. Error:" << GetLastError() << std::endl;return;}pHandleData->socket = acceptSocket;if ( CreateIoCompletionPort( (HANDLE)acceptSocket, completionPort, (ULONG_PTR)pHandleData, 0 ) == NULL ){std::cout << "CreateIoCompletionPort failed. Error:" << GetLastError() << std::endl;return;}pIoData = ( LPPER_IO_OPERATION_DATA )GlobalAlloc( GPTR, sizeof( PER_IO_OPERATEION_DATA ) );if ( pIoData == NULL ){std::cout << "GlobalAlloc( IoData ) failed. Error:" << GetLastError() << std::endl;return;}ZeroMemory( &( pIoData->overlapped ), sizeof( pIoData->overlapped ) );pIoData->bytesSend = 0;pIoData->bytesRecv = 0;pIoData->databuff.len = DataBuffSize;pIoData->databuff.buf = pIoData->buffer;flags = 0;if ( WSARecv( acceptSocket, &(pIoData->databuff), 1, &recvBytes, &flags, &(pIoData->overlapped), NULL ) == SOCKET_ERROR ){if ( WSAGetLastError() != ERROR_IO_PENDING ){std::cout << "WSARecv() failed. Error:" << GetLastError() << std::endl;return;}else{std::cout << "WSARecv() io pending" << std::endl;return;}}}}DWORD WINAPI ServerWorkThread( LPVOID CompletionPortID ){HANDLE complationPort = (HANDLE)CompletionPortID;DWORD bytesTransferred;LPPER_HANDLE_DATA pHandleData = NULL;LPPER_IO_OPERATION_DATA pIoData = NULL;DWORD sendBytes = 0;DWORD recvBytes = 0;DWORD flags;while ( 1 ){if ( GetQueuedCompletionStatus( complationPort, &bytesTransferred, (PULONG_PTR)&pHandleData, (LPOVERLAPPED *)&pIoData, INFINITE ) == 0 ){std::cout << "GetQueuedCompletionStatus failed. Error:" << GetLastError() << std::endl;return 0;}// 检查数据是否已经传输完了if ( bytesTransferred == 0 ){std::cout << " Start closing socket..." << std::endl;if ( CloseHandle( (HANDLE)pHandleData->socket ) == SOCKET_ERROR ){std::cout << "Close socket failed. Error:" << GetLastError() << std::endl;return 0;}GlobalFree( pHandleData );GlobalFree( pIoData );continue;}// 检查管道里是否有数据if ( pIoData->bytesRecv == 0 ){pIoData->bytesRecv = bytesTransferred;pIoData->bytesSend = 0;}else{pIoData->bytesSend += bytesTransferred;}// 数据没有发完,继续发送if ( pIoData->bytesRecv > pIoData->bytesSend ){ZeroMemory( &(pIoData->overlapped), sizeof( OVERLAPPED ) );pIoData->databuff.buf = pIoData->buffer + pIoData->bytesSend;pIoData->databuff.len = pIoData->bytesRecv - pIoData->bytesSend;// 发送数据出去if ( WSASend( pHandleData->socket, &(pIoData->databuff), 1, &sendBytes, 0, &(pIoData->overlapped), NULL ) == SOCKET_ERROR ){if ( WSAGetLastError() != ERROR_IO_PENDING ){std::cout << "WSASend() failed. Error:" << GetLastError() << std::endl;return 0;}else{std::cout << "WSASend() failed. io pending. Error:" << GetLastError() << std::endl;return 0;}}std::cout << "Send " << pIoData->buffer << std::endl;}else{pIoData->bytesRecv = 0;flags = 0;ZeroMemory( &(pIoData->overlapped), sizeof( OVERLAPPED ) );pIoData->databuff.len = DataBuffSize;pIoData->databuff.buf = pIoData->buffer;if ( WSARecv( pHandleData->socket, &(pIoData->databuff), 1, &recvBytes, &flags, &(pIoData->overlapped), NULL ) == SOCKET_ERROR ){if ( WSAGetLastError() != ERROR_IO_PENDING ){std::cout << "WSARecv() failed. Error:" << GetLastError() << std::endl;return 0;}else{std::cout << "WSARecv() io pending" << std::endl;return 0;}}}}}


 

整个过程还是类似于最基础的socket连接方式,主要部分就是使用IOCP的两个函数,创建IOCP和检测当前的状态。

大家先凑活看吧,后面本博客会有更精彩的IOCP内容呈现给大家,我也是逐步在学习,大家稍安勿躁。

 

0 0