轉發:IOCP模型示例程式碼
阿新 • • 發佈:2018-12-10
#include <WinSock2.h> #include <Windows.h> #include <vector> #include <iostream> using namespace std; #pragma comment(lib, "ws2_32.lib") //socket動態連結庫 #pragma comment(lib, "kernel32.lib") //IOCP動態連結庫 //重疊IO用到的結構體,記錄IO資料 const int DataBufferSize = 2* 1024; typedef struct s1 { OVERLAPPED overlapped; WSABUF databuff; char cBuffer[DataBufferSize]; int BufferLen; int OperationType; }PER_IO_DATA, *LPPER_IO_DATA; //記錄每個連線的socket資訊 typedef struct { SOCKET socket; SOCKADDR_STORAGE clientAddr; }PER_HANDLE_DATA, * LPPER_HANDLE_DATA; //定義全域性變數 const int nDefaultPort = 6000; vector<PER_HANDLE_DATA *> g_vClientGroup;//記錄客戶端的容器 HANDLE hMutex = CreateMutex(NULL, FALSE, NULL); DWORD WINAPI ServerWorkThread(LPVOID CompletionPortID); DWORD WINAPI ServerSendThread(LPVOID lpParam); int main() { WORD wVersionRequested = MAKEWORD(2,2);//請求版本為2.2的WINSOCKET庫 WSADATA wsaData; //接收windows socket的結構資訊 DWORD err = WSAStartup(wVersionRequested, &wsaData); if(0 != err) { cout<<"Request Windows Socket Library Error!"<<endl; return -1; } if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { WSACleanup(); cout<<"Request Windows Socket Version 2.2 Error!"<<endl; return -1; } //建立IOCP的核心物件 HANDLE completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if(NULL == completionPort) { cout<<"CreateIoCompletionPort failed Error!"<<GetLastError()<<endl; return -1; } //建立處理器的核心數量 SYSTEM_INFO mySysInfo; GetSystemInfo(&mySysInfo); //建立工作執行緒 for(DWORD i = 0; i < (mySysInfo.dwNumberOfProcessors * 2); i++) { HANDLE ThreadHandle = CreateThread(NULL, 0, ServerWorkThread, completionPort, 0, NULL); if(NULL == ThreadHandle) { cout<<"Create Thread Handle failed Error:"<<GetLastError()<<endl; return -1; } CloseHandle(ThreadHandle); } //建立伺服器套接字 SOCKET srvSocket = socket(AF_INET, SOCK_STREAM, 0); //繫結SOCKET到本機 SOCKADDR_IN srvAddr; srvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(nDefaultPort); int nBindResult = bind(srvSocket, (SOCKADDR *)&srvAddr, sizeof(SOCKADDR)); if(SOCKET_ERROR == nBindResult) { cout<<"Bind failed Error:"<<GetLastError()<<endl; return -1; } //將socket設定為監聽模式 int nListenResult = listen(srvSocket, SOMAXCONN); if(SOCKET_ERROR == nListenResult) { cout<<"Listen failed Error:"<<GetLastError()<<endl; return -1; } cout<<"伺服器已啟動,等待客戶端連線..."<<endl; //建立用於傳送資料的執行緒 HANDLE sendThread = CreateThread(NULL, 0, ServerSendThread, 0, 0, NULL); while(true) { PER_HANDLE_DATA * lpPer_Handle_Data = NULL; SOCKADDR_IN sockaddr_client; int nsocketaddr_client; SOCKET acceptSocket; nsocketaddr_client = sizeof(sockaddr_client); acceptSocket = accept(srvSocket, (sockaddr *)&sockaddr_client, &nsocketaddr_client); if(SOCKET_ERROR == acceptSocket) { cout<<"Accept Socket Error:"<<GetLastError()<<endl; return -1; } //建立用來和套接字關聯的單控制代碼資料資訊結構 lpPer_Handle_Data = new PER_HANDLE_DATA; lpPer_Handle_Data->socket = acceptSocket; memcpy(&lpPer_Handle_Data->clientAddr, &sockaddr_client, nsocketaddr_client); g_vClientGroup.push_back(lpPer_Handle_Data); //將接收套接字和完成埠關聯 CreateIoCompletionPort((HANDLE)(lpPer_Handle_Data->socket), completionPort, (DWORD)lpPer_Handle_Data, 0); LPPER_IO_DATA perIoData = NULL; memset(perIoData, 0, sizeof(struct s1)); //perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA)); //perIoData = new PER_IO_DATA; //ZeroMemory(&(perIoData->overlapped), sizeof(OVERLAPPED)); perIoData->databuff.len = 1024; perIoData->databuff.buf = perIoData->cBuffer; perIoData->OperationType = 0; //read DWORD RecvBytes; DWORD Flags = 0; WSARecv(lpPer_Handle_Data->socket, &(perIoData->databuff), 1, &RecvBytes, &Flags, &(perIoData->overlapped), NULL); } return 0; } //開始伺服器工作執行緒函式 DWORD WINAPI ServerWorkThread(LPVOID IpParam) { HANDLE CompletionPort = (HANDLE)IpParam; DWORD BytesTransferred; LPOVERLAPPED IpOverlapped; LPPER_HANDLE_DATA PerHandleData = NULL; LPPER_IO_DATA lpPerIoData = NULL; DWORD RecvBytes; DWORD Flags = 0; BOOL bRet = false; while(true) { bRet = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR)&PerHandleData, (LPOVERLAPPED *)&IpOverlapped, INFINITE); if(bRet == 0) { cout<<"GetQueuedCompletionStatus Error:"<<GetLastError()<<endl; return -1; } lpPerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(IpOverlapped, PER_IO_DATA, overlapped); if(0 == BytesTransferred) { closesocket(PerHandleData->socket); GlobalFree(PerHandleData); GlobalFree(lpPerIoData); continue; } //開始資料處理,接收來至客戶端的資料 WaitForSingleObject(hMutex, INFINITE); cout<<"A Client says:"<<lpPerIoData->databuff.buf<<endl; ReleaseMutex(hMutex); //為下一個重疊呼叫建立單I/O操作資料 ZeroMemory(&(lpPerIoData->overlapped), sizeof(OVERLAPPED)); //清空記憶體 lpPerIoData->databuff.len = 1024; lpPerIoData->databuff.buf = lpPerIoData->cBuffer; lpPerIoData->OperationType = 0; WSARecv(PerHandleData->socket, &(lpPerIoData->databuff), 1, &RecvBytes, &Flags, &(lpPerIoData->overlapped), NULL); } return 0; } DWORD WINAPI ServerSendThread(LPVOID IpParam) { while(true) { char talk[200]={0x00}; gets(talk); int len; for(len=0; talk[len] != '\0'; ++len) { } talk[len]='\n'; talk[++len] = '\0'; cout<<"I Say :"; cout<<talk<<endl; WaitForSingleObject(hMutex, INFINITE); for(int i=0; i<g_vClientGroup.size(); i++) { send(g_vClientGroup[i]->socket, talk, 200, 0); } ReleaseMutex(hMutex); } return 0; }