轉自于:http://hi.baidu.com/netpet/blog/item/bb5ebdb7fd4650f030add1a1.html
代碼如下,注釋已經全部改成中文
#include?? <winsock2.h>??
//#include?? <windows.h>??
#include?? <stdio.h>??
#define?? PORT?? 5150??
#define?? DATA_BUFSIZE?? 8192??
???
typedef?? struct??
{??
??????? OVERLAPPED?? Overlapped;??
??????? WSABUF?? DataBuf;??
??????? CHAR?? Buffer[DATA_BUFSIZE];??
??????? DWORD?? BytesSEND;??
??????? DWORD?? BytesRECV;??
}?? PER_IO_OPERATION_DATA,?? *?? LPPER_IO_OPERATION_DATA;??
???
???
typedef?? struct????
{??
??????? SOCKET?? Socket;??
}?? PER_HANDLE_DATA,?? *?? LPPER_HANDLE_DATA;??
???
???
DWORD?? WINAPI?? ServerWorkerThread(LPVOID?? CompletionPortID);??
???
int main(void)??
{??
??????? SOCKADDR_IN?? InternetAddr;??
??????? SOCKET?? Listen;??
??????? SOCKET?? Accept;??
??????? HANDLE?? CompletionPort;??
??????? SYSTEM_INFO?? SystemInfo;??
??????? LPPER_HANDLE_DATA?? PerHandleData;??
??????? LPPER_IO_OPERATION_DATA?? PerIoData;??
??????? int?? i;??
??????? DWORD?? RecvBytes;??
??????? DWORD?? Flags;??
??????? DWORD?? ThreadID;??
??????? WSADATA?? wsaData;??
??????? DWORD?? Ret;??
???
??????? if?? ((Ret?? =?? WSAStartup(0x0202,?? &wsaData))?? !=?? 0)??
??????? {??
????????????? printf("WSAStartup失敗了,錯誤信息如下:?? %d\n",?? Ret);??
????????????? return;??
??????? }??
???
??????? // 設置一個I/O完成端口.??
???
??????? if?? ((CompletionPort?? =?? CreateIoCompletionPort(INVALID_HANDLE_VALUE,?? NULL,?? 0,?? 0))?? ==?? NULL)??
??????? {??
????????????? printf(?? "CreateIoCompletionPort 失敗了,錯誤信息如下:?? %d\n",?? GetLastError());??
????????????? return;??
??????? }??
???
??????? // 測試系統中有多少cpu處理器
???
??????? GetSystemInfo(&SystemInfo);??
???
??????? //?? 基于系統可用的處理器創建工作線程,為每個處理器創建連個線程??
???
??????? for(i?? =?? 0;?? i?? <?? SystemInfo.dwNumberOfProcessors?? *?? 2;?? i++)??
??????? {??
????????????? HANDLE?? ThreadHandle;??
???
????????????? // 創建一個服務端線程并且傳遞一個完成端口給這個線程.??
???
????????????? if?? ((ThreadHandle?? =?? CreateThread(NULL,?? 0,?? ServerWorkerThread,?? CompletionPort,??
??????????????????? 0,?? &ThreadID))?? ==?? NULL)??
????????????? {??
??????????????????? printf("CreateThread()發生了如下錯誤: %d\n",?? GetLastError());??
??????????????????? return;??
????????????? }??
????????????? else
????????????? {printf("創建了一個完成端口.\n");
????????????? }
????????????? //?? 關閉 thread句柄
????????????? CloseHandle(ThreadHandle);??
??????? }??
???
??????? //?? 創建一個監聽套接字
???
??????? if?? ((Listen?? =WSASocket(AF_INET,?? SOCK_STREAM,?? 0,?? NULL,0,WSA_FLAG_OVERLAPPED))?? ==?? INVALID_SOCKET)??
??????? {??
????????????? printf("WSASocket() 發生了如下錯誤: %d\n",?? WSAGetLastError());??
????????????? return;??
??????? }
??????? else????
??????? {printf("創建監聽套接字成功\n");}
??????? InternetAddr.sin_family?? =?? AF_INET;??
??????? InternetAddr.sin_addr.s_addr?? =?? htonl(INADDR_ANY);??
??????? InternetAddr.sin_port?? =?? htons(PORT);??
???
??????? if?? (bind(Listen,?? (PSOCKADDR)?? &InternetAddr,?? sizeof(InternetAddr))?? ==?? SOCKET_ERROR)??
??????? {??
????????????? printf("bind()端口或IP時發生了如下錯誤: %d\n",?? WSAGetLastError());??
????????????? return;??
??????? }??
??????? else
??????? {printf("綁定端口%d成功\n",PORT);}
??????? // 準備socket 用來監聽??
???
??????? if?? (listen(Listen,?? 5)?? ==?? SOCKET_ERROR)??
??????? {??
????????????? printf("listen() 發生了如下錯誤?? %d\n",?? WSAGetLastError());??
????????????? return;??
??????? }??
???????? else
??????? {printf("預處理成功,開始在端口 %d 處監聽...\n",PORT);}
??????? //接受連接并且交給完成端口處理
???
??????? while(TRUE)??
??????? {??
????????????? if?? ((Accept?? =?? WSAAccept(Listen,?? NULL,?? NULL,?? NULL,?? 0))?? ==?? SOCKET_ERROR)??
????????????? {??
??????????????????? printf("WSAAccept()?? 發生了如下錯誤:?? %d\n",?? WSAGetLastError());??
??????????????????? return;??
????????????? }??
???
????????????? // 創建一個套接字信息結構體去聯系起來socket??
????????????? if?? ((PerHandleData?? =?? (LPPER_HANDLE_DATA)?? GlobalAlloc(GPTR,????
??????????????????? sizeof(PER_HANDLE_DATA)))?? ==?? NULL)??
????????????? {??
??????????????????? printf("GlobalAlloc()?? 發生了如下錯誤:?? %d\n",?? GetLastError());??
??????????????????? return;??
????????????? }??
???
????????????? // 將接受到的套接字與原始的完成端口聯系起來.??
???
????????????? printf("號碼為?? %d?? 的socket連接上了\n",?? Accept);??
????????????? PerHandleData->Socket?? =?? Accept;??
???
????????????? if?? (CreateIoCompletionPort((HANDLE)?? Accept,?? CompletionPort,?? (DWORD)?? PerHandleData,??
??????????????????? 0)?? ==?? NULL)??
????????????? {??
??????????????????? printf("CreateIoCompletionPort?? 發生了如下錯誤:?? %d\n",?? GetLastError());??
??????????????????? return;??
????????????? }??
???
????????????? //?? 創建每一個I/O 套接字信息結構體去和下面被調用的 to?? associate?? with?? the????
????????????? //?? WSARecv 連接.??
???
????????????? if?? ((PerIoData?? =?? (LPPER_IO_OPERATION_DATA)?? GlobalAlloc(GPTR,???????????????????? sizeof(PER_IO_OPERATION_DATA)))?? ==?? NULL)??
????????????? {??
??????????????????? printf("GlobalAlloc() 發生了如下錯誤: %d\n",?? GetLastError());??
??????????????????? return;??
????????????? }??
????????????? else{printf("接收了一個連接\n");}
????????????? ZeroMemory(&(PerIoData->Overlapped),?? sizeof(OVERLAPPED));??
????????????? PerIoData->BytesSEND?? =?? 0;??
????????????? PerIoData->BytesRECV?? =?? 0;??
????????????? PerIoData->DataBuf.len?? =?? DATA_BUFSIZE;??
????????????? PerIoData->DataBuf.buf?? =?? PerIoData->Buffer;??
???
????????????? Flags?? =?? 0;??
????????????? if?? (WSARecv(Accept,?? &(PerIoData->DataBuf),?? 1,?? &RecvBytes,?? &Flags,??
??????????????????? &(PerIoData->Overlapped),?? NULL)?? ==?? SOCKET_ERROR)??
????????????? {??
??????????????????? if?? (WSAGetLastError()?? !=?? ERROR_IO_PENDING)??
??????????????????? {??
????????????????????????? printf("WSARecv() 發生了如下錯誤: %d\n",?? WSAGetLastError());??
????????????????????????? return;??
??????????????????? }??
????????????? }??
??????? }??
}??
???
DWORD?? WINAPI?? ServerWorkerThread(LPVOID?? CompletionPortID)??
{??
??????? HANDLE?? CompletionPort?? =?? (HANDLE)?? CompletionPortID;??
??????? DWORD?? BytesTransferred;??
??????? LPOVERLAPPED?? Overlapped;??
??????? LPPER_HANDLE_DATA?? PerHandleData;??
??????? LPPER_IO_OPERATION_DATA?? PerIoData;??
??????? DWORD?? SendBytes,?? RecvBytes;??
??????? DWORD?? Flags;??
?????????
??????? while(TRUE)??
??????? {??
???
????????????? if?? (GetQueuedCompletionStatus(CompletionPort,?? &BytesTransferred,??
??????????????????? (LPDWORD)&PerHandleData,?? (LPOVERLAPPED?? *)?? &PerIoData,?? INFINITE)?? ==?? 0)??
????????????? {??
??????????????????? printf("GetQueuedCompletionStatus?? 發生了如下錯誤: %d\n",?? GetLastError());??
??????????????????? return?? 0;??
????????????? }??
???
????????????? //首先檢查一下去套接字看是否在上發生了錯誤并且如果發生了錯誤就關閉套接
????????????? //字并且清除與套接字連接的 SOCKET_INFORMATION結構信息體
????????????? if?? (BytesTransferred?? ==?? 0)??
????????????? {??
??????????????????? printf("正在關閉socket?? %d\n",?? PerHandleData->Socket);??
???
??????????????????? if?? (closesocket(PerHandleData->Socket)?? ==?? SOCKET_ERROR)??
??????????????????? {??
????????????????????????? printf("closesocket()?? 發生了如下錯誤: %d\n",?? WSAGetLastError());??
????????????????????????? return?? 0;??
??????????????????? }??
???
??????????????????? GlobalFree(PerHandleData);??
??????????????????? GlobalFree(PerIoData);??
??????????????????? continue;??
????????????? }??
??? //檢查如果 BytesRECV字段等于0,這就意味著一個 WSARecv調用剛剛完成了所以從完成的WSARecv()調用中
??? //用BytesTransferred值更新 BytesRECV字段
????????????? if?? (PerIoData->BytesRECV?? ==?? 0)??
????????????? {??
??????????????????? PerIoData->BytesRECV?? =?? BytesTransferred;??
??????????????????? PerIoData->BytesSEND?? =?? 0;??
????????????? }??
????????????? else??
????????????? {??
??????????????????? PerIoData->BytesSEND?? +=?? BytesTransferred;??
????????????? }??
???
????????????? if?? (PerIoData->BytesRECV?? >?? PerIoData->BytesSEND)??
????????????? {??
??? //發布另外一個 WSASend()請求
??? //既然WSASend()不是 gauranteed去發送所有字節的請求
??? //繼續調用 WSASend()發送直到所有收到的字節被發送
???????????????????
??????????????????? ZeroMemory(&(PerIoData->Overlapped),?? sizeof(OVERLAPPED));??
???
??????????????????? PerIoData->DataBuf.buf?? =?? PerIoData->Buffer?? +?? PerIoData->BytesSEND;??
??????????????????? PerIoData->DataBuf.len?? =?? PerIoData->BytesRECV?? -?? PerIoData->BytesSEND;??
???
??????????????????? if?? (WSASend(PerHandleData->Socket,?? &(PerIoData->DataBuf),?? 1,?? &SendBytes,?? 0,??
????????????????????????? &(PerIoData->Overlapped),?? NULL)?? ==?? SOCKET_ERROR)??
??????????????????? {??
????????????????????????? if?? (WSAGetLastError()?? !=?? ERROR_IO_PENDING)??
????????????????????????? {??
??????????????????????????????? printf("WSASend() 發生了如下錯誤:?? %d\n",?? WSAGetLastError());??
??????????????????????????????? return?? 0;??
????????????????????????? }??
??????????????????? }??
????????????? }??
????????????? else??
????????????? {??
??????????????????? PerIoData->BytesRECV?? =?? 0;??
??? //現在沒有更多的字節發送過去用來post另外一個WSARecv()請求
???????????????????
??????????????????? Flags?? =?? 0;??
??????????????????? ZeroMemory(&(PerIoData->Overlapped),?? sizeof(OVERLAPPED));??
???
??????????????????? PerIoData->DataBuf.len?? =?? DATA_BUFSIZE;??
??????????????????? PerIoData->DataBuf.buf?? =?? PerIoData->Buffer;??
???
??????????????????? if?? (WSARecv(PerHandleData->Socket,?? &(PerIoData->DataBuf),?? 1,?? &RecvBytes,?? &Flags,??
????????????????????????? &(PerIoData->Overlapped),?? NULL)?? ==?? SOCKET_ERROR)??
??????????????????? {??
????????????????????????? if?? (WSAGetLastError()?? !=?? ERROR_IO_PENDING)??
????????????????????????? {??
??????????????????????????????? printf("WSARecv() 發生了如下錯誤:?? %d\n",?? WSAGetLastError());??
??????????????????????????????? return?? 0;??
????????????????????????? }??
??????????????????? }??
????????????? }??
??????? }??
}??