使用IOCP模型编程的优点
① 帮助维持重复使用的内存池。(与重叠I/O技术有关)
② 去除删除线程创建/终结负担。
③ 利于管理,分配线程,控制并发,最小化的线程上下文切换。
④ 优化线程调度,提高CPU和内存缓冲的命中率。
服务器:
<code class="hljs cpp has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// IOCP_TCPIP_Socket_Server.cpp</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <WinSock2.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <Windows.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <vector></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <iostream></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">namespace</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>; <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma comment(lib, "Ws2_32.lib") <span class="hljs-comment" style="box-sizing: border-box;">// Socket编程需用的动态链接库</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma comment(lib, "Kernel32.lib") <span class="hljs-comment" style="box-sizing: border-box;">// IOCP需要用到的动态链接库</span></span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 结构体名称:PER_IO_DATA * 结构体功能:重叠I/O需要用到的结构体,临时记录IO数据 **/</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> DataBuffSize = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> { OVERLAPPED overlapped; WSABUF databuff; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> buffer[DataBuffSize]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> BufferLen; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> operationType; }PER_IO_OPERATEION_DATA, *LPPER_IO_OPERATION_DATA, *LPPER_IO_DATA, PER_IO_DATA; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 结构体名称:PER_HANDLE_DATA * 结构体存储:记录单个套接字的数据,包括了套接字的变量及套接字的对应的客户端的地址。 * 结构体作用:当服务器连接上客户端时,信息存储到该结构体中,知道客户端的地址以便于回访。 **/</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> { SOCKET socket; SOCKADDR_STORAGE ClientAddr; }PER_HANDLE_DATA, *LPPER_HANDLE_DATA; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 定义全局变量</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> DefaultPort = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5000</span>; <span class="hljs-stl_container" style="box-sizing: border-box;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">vector</span> < PER_HANDLE_DATA* ></span> clientGroup; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 记录客户端的向量组</span> <span class="hljs-stl_container" style="box-sizing: border-box;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">vector</span><LPPER_IO_OPERATION_DATA></span> IOOperationDataGroup; HANDLE hMutex = CreateMutex(NULL, FALSE, NULL); DWORD WINAPI ServerWorkThread(LPVOID CompletionPortID); DWORD WINAPI ServerSendThread(LPVOID IpParam); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 开始主函数</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main() { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 加载socket动态链接库</span> WORD wVersionRequested = MAKEWORD(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 请求2.2版本的WinSock库</span> WSADATA wsaData; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 接收Windows Socket的结构信息</span> DWORD err = WSAStartup(wVersionRequested, &wsaData); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> != err) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查套接字库是否申请成功</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Request Windows Socket Library Error!\n"</span>; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (LOBYTE(wsaData.wVersion) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> || HIBYTE(wsaData.wVersion) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>) {<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查是否申请了所需版本的套接字库</span> WSACleanup(); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Request Windows Socket Version 2.2 Error!\n"</span>; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建IOCP的内核对象</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 需要用到的函数的原型: * HANDLE WINAPI CreateIoCompletionPort( * __in HANDLE FileHandle, // 已经打开的文件句柄或者空句柄,一般是客户端的句柄 * __in HANDLE ExistingCompletionPort, // 已经存在的IOCP句柄 * __in ULONG_PTR CompletionKey, // 完成键,包含了指定I/O完成包的指定文件 * __in DWORD NumberOfConcurrentThreads // 真正并发同时执行最大线程数,一般推介是CPU核心数*2 * ); **/</span> HANDLE completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (NULL == completionPort) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建IO内核对象失败</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"CreateIoCompletionPort failed. Error:"</span> << GetLastError() << endl; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建IOCP线程--线程里面创建线程池</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 确定处理器的核心数量</span> SYSTEM_INFO mySysInfo; GetSystemInfo(&mySysInfo); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 基于处理器的核心数量创建线程</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (DWORD i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < (mySysInfo.dwNumberOfProcessors * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); ++i) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建服务器工作器线程,并将完成端口传递到该线程</span> HANDLE ThreadHandle = CreateThread(NULL, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, ServerWorkThread, completionPort, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, NULL);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//第一NULL代表默认安全选项,第一个0,代表线程占用资源大小,第二个0,代表线程创建后立即执行</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (NULL == ThreadHandle) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Create Thread Handle failed. Error:"</span> << GetLastError() << endl; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } CloseHandle(ThreadHandle); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 建立流式套接字</span> SOCKET srvSocket = socket(AF_INET, SOCK_STREAM, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 绑定SOCKET到本机</span> SOCKADDR_IN srvAddr; srvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(DefaultPort); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> bindResult = bind(srvSocket, (SOCKADDR*)&srvAddr, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(SOCKADDR)); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (SOCKET_ERROR == bindResult) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Bind failed. Error:"</span> << GetLastError() << endl; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将SOCKET设置为监听模式</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> listenResult = listen(srvSocket, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (SOCKET_ERROR == listenResult) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Listen failed. Error: "</span> << GetLastError() << endl; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 开始处理IO数据</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"本服务器已准备就绪,正在等待客户端的接入...\n"</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> 创建用于发送数据的线程</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//HANDLE sendThread = CreateThread(NULL, 0, ServerSendThread, 0, 0, NULL);//第二个0,代表回掉函数参数为0</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) { PER_HANDLE_DATA * PerHandleData = NULL; SOCKADDR_IN saRemote; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> RemoteLen; SOCKET acceptSocket; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 接收连接,并分配完成端,这儿可以用AcceptEx()</span> RemoteLen = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(saRemote); acceptSocket = accept(srvSocket, (SOCKADDR*)&saRemote, &RemoteLen); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (SOCKET_ERROR == acceptSocket) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 接收客户端失败</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Accept Socket Error: "</span> << GetLastError() << endl; system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建用来和套接字关联的单句柄数据信息结构</span> PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(PER_HANDLE_DATA)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 在堆中为这个PerHandleData申请指定大小的内存</span> PerHandleData->socket = acceptSocket; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">memcpy</span>(&PerHandleData->ClientAddr, &saRemote, RemoteLen); clientGroup.push_back(PerHandleData); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将单个客户端数据指针放到客户端组中</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将接受套接字和完成端口关联</span> CreateIoCompletionPort((HANDLE)(PerHandleData->socket), completionPort, (DWORD)PerHandleData, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 开始在接受套接字上处理I/O使用重叠I/O机制</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 在新建的套接字上投递一个或多个异步</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// WSARecv或WSASend请求,这些I/O请求完成后,工作者线程会为I/O请求提供服务 </span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 单I/O操作数据(I/O重叠)</span> LPPER_IO_OPERATION_DATA PerIoData = NULL; PerIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(PER_IO_OPERATEION_DATA)); ZeroMemory(&(PerIoData->overlapped), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(OVERLAPPED)); PerIoData->databuff.len = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span>; PerIoData->databuff.buf = PerIoData->buffer; PerIoData->operationType = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// read</span> IOOperationDataGroup.push_back(PerIoData); DWORD RecvBytes; DWORD Flags = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//WSARecv中的1,代表缓冲区lpBuffers只包含一个WSABUF,Flags代表接收普通数据</span> WSARecv(PerHandleData->socket, &(PerIoData->databuff), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, &RecvBytes, &Flags, &(PerIoData->overlapped), NULL);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//PerIoData->overlapped就是CONTAINING_RECORD的第一个变量</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">auto</span> it = IOOperationDataGroup.begin(); it != IOOperationDataGroup.end(); it++) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (*it != NULL) GlobalFree(*it); } system(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pause"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 开始服务工作线程函数</span> DWORD WINAPI ServerWorkThread(LPVOID IpParam) { HANDLE CompletionPort = (HANDLE)IpParam; DWORD BytesTransferred; LPOVERLAPPED IpOverlapped; LPPER_HANDLE_DATA PerHandleData = NULL; LPPER_IO_DATA PerIoData = NULL; DWORD RecvBytes; DWORD Flags = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; BOOL bRet = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) { bRet = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR)&PerHandleData, (LPOVERLAPPED*)&IpOverlapped, INFINITE);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//此处可以将IpOverlapped换为PerIoData,然后将下面CONTAINING_RECORD注释掉</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (bRet == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"GetQueuedCompletionStatus Error: "</span> << GetLastError() << endl; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; } PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(IpOverlapped, PER_IO_DATA, overlapped); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//这个宏的作用是:根据一个结构体实例中的成员的地址,取到整个结构体实例的地址</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//PER_IO_DATA的成员overlapped的地址为&IpOverlapped,结果就可以获得PER_IO_DATA的地址</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查在套接字上是否有错误发生</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> == BytesTransferred) { closesocket(PerHandleData->socket); GlobalFree(PerHandleData); GlobalFree(PerIoData); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 开始数据处理,接收来自客户端的数据</span> WaitForSingleObject(hMutex, INFINITE); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"A Client says: "</span> << PerIoData->databuff.buf << endl; ReleaseMutex(hMutex); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 为下一个重叠调用建立单I/O操作数据</span> ZeroMemory(&(PerIoData->overlapped), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(OVERLAPPED)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 清空内存</span> PerIoData->databuff.len = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span>; PerIoData->databuff.buf = PerIoData->buffer;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//buf是个指针,这一过程会清空buffer的内容</span> PerIoData->operationType = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// read</span> WSARecv(PerHandleData->socket, &(PerIoData->databuff), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, &RecvBytes, &Flags, &(PerIoData->overlapped), NULL); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 发送信息的线程执行函数</span> DWORD WINAPI ServerSendThread(LPVOID IpParam) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (clientGroup.empty()) { Sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5000</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> talk[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>]; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cin</span>.get(talk,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> len; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (len = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; talk[len] != <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\0'</span>; ++len) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 找出这个字符组的长度</span> } talk[len] = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>; talk[++len] = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\0'</span>; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"I Say:"</span>); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << talk; WaitForSingleObject(hMutex, INFINITE); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < clientGroup.size(); ++i) { send(clientGroup[i]->socket, talk, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 发送信息</span> } ReleaseMutex(hMutex); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li><li style="box-sizing: border-box; padding: 0px 5px;">124</li><li style="box-sizing: border-box; padding: 0px 5px;">125</li><li style="box-sizing: border-box; padding: 0px 5px;">126</li><li style="box-sizing: border-box; padding: 0px 5px;">127</li><li style="box-sizing: border-box; padding: 0px 5px;">128</li><li style="box-sizing: border-box; padding: 0px 5px;">129</li><li style="box-sizing: border-box; padding: 0px 5px;">130</li><li style="box-sizing: border-box; padding: 0px 5px;">131</li><li style="box-sizing: border-box; padding: 0px 5px;">132</li><li style="box-sizing: border-box; padding: 0px 5px;">133</li><li style="box-sizing: border-box; padding: 0px 5px;">134</li><li style="box-sizing: border-box; padding: 0px 5px;">135</li><li style="box-sizing: border-box; padding: 0px 5px;">136</li><li style="box-sizing: border-box; padding: 0px 5px;">137</li><li style="box-sizing: border-box; padding: 0px 5px;">138</li><li style="box-sizing: border-box; padding: 0px 5px;">139</li><li style="box-sizing: border-box; padding: 0px 5px;">140</li><li style="box-sizing: border-box; padding: 0px 5px;">141</li><li style="box-sizing: border-box; padding: 0px 5px;">142</li><li style="box-sizing: border-box; padding: 0px 5px;">143</li><li style="box-sizing: border-box; padding: 0px 5px;">144</li><li style="box-sizing: border-box; padding: 0px 5px;">145</li><li style="box-sizing: border-box; padding: 0px 5px;">146</li><li style="box-sizing: border-box; padding: 0px 5px;">147</li><li style="box-sizing: border-box; padding: 0px 5px;">148</li><li style="box-sizing: border-box; padding: 0px 5px;">149</li><li style="box-sizing: border-box; padding: 0px 5px;">150</li><li style="box-sizing: border-box; padding: 0px 5px;">151</li><li style="box-sizing: border-box; padding: 0px 5px;">152</li><li style="box-sizing: border-box; padding: 0px 5px;">153</li><li style="box-sizing: border-box; padding: 0px 5px;">154</li><li style="box-sizing: border-box; padding: 0px 5px;">155</li><li style="box-sizing: border-box; padding: 0px 5px;">156</li><li style="box-sizing: border-box; padding: 0px 5px;">157</li><li style="box-sizing: border-box; padding: 0px 5px;">158</li><li style="box-sizing: border-box; padding: 0px 5px;">159</li><li style="box-sizing: border-box; padding: 0px 5px;">160</li><li style="box-sizing: border-box; padding: 0px 5px;">161</li><li style="box-sizing: border-box; padding: 0px 5px;">162</li><li style="box-sizing: border-box; padding: 0px 5px;">163</li><li style="box-sizing: border-box; padding: 0px 5px;">164</li><li style="box-sizing: border-box; padding: 0px 5px;">165</li><li style="box-sizing: border-box; padding: 0px 5px;">166</li><li style="box-sizing: border-box; padding: 0px 5px;">167</li><li style="box-sizing: border-box; padding: 0px 5px;">168</li><li style="box-sizing: border-box; padding: 0px 5px;">169</li><li style="box-sizing: border-box; padding: 0px 5px;">170</li><li style="box-sizing: border-box; padding: 0px 5px;">171</li><li style="box-sizing: border-box; padding: 0px 5px;">172</li><li style="box-sizing: border-box; padding: 0px 5px;">173</li><li style="box-sizing: border-box; padding: 0px 5px;">174</li><li style="box-sizing: border-box; padding: 0px 5px;">175</li><li style="box-sizing: border-box; padding: 0px 5px;">176</li><li style="box-sizing: border-box; padding: 0px 5px;">177</li><li style="box-sizing: border-box; padding: 0px 5px;">178</li><li style="box-sizing: border-box; padding: 0px 5px;">179</li><li style="box-sizing: border-box; padding: 0px 5px;">180</li><li style="box-sizing: border-box; padding: 0px 5px;">181</li><li style="box-sizing: border-box; padding: 0px 5px;">182</li><li style="box-sizing: border-box; padding: 0px 5px;">183</li><li style="box-sizing: border-box; padding: 0px 5px;">184</li><li style="box-sizing: border-box; padding: 0px 5px;">185</li><li style="box-sizing: border-box; padding: 0px 5px;">186</li><li style="box-sizing: border-box; padding: 0px 5px;">187</li><li style="box-sizing: border-box; padding: 0px 5px;">188</li><li style="box-sizing: border-box; padding: 0px 5px;">189</li><li style="box-sizing: border-box; padding: 0px 5px;">190</li><li style="box-sizing: border-box; padding: 0px 5px;">191</li><li style="box-sizing: border-box; padding: 0px 5px;">192</li><li style="box-sizing: border-box; padding: 0px 5px;">193</li><li style="box-sizing: border-box; padding: 0px 5px;">194</li><li style="box-sizing: border-box; padding: 0px 5px;">195</li><li style="box-sizing: border-box; padding: 0px 5px;">196</li><li style="box-sizing: border-box; padding: 0px 5px;">197</li><li style="box-sizing: border-box; padding: 0px 5px;">198</li><li style="box-sizing: border-box; padding: 0px 5px;">199</li><li style="box-sizing: border-box; padding: 0px 5px;">200</li><li style="box-sizing: border-box; padding: 0px 5px;">201</li><li style="box-sizing: border-box; padding: 0px 5px;">202</li><li style="box-sizing: border-box; padding: 0px 5px;">203</li><li style="box-sizing: border-box; padding: 0px 5px;">204</li><li style="box-sizing: border-box; padding: 0px 5px;">205</li><li style="box-sizing: border-box; padding: 0px 5px;">206</li><li style="box-sizing: border-box; padding: 0px 5px;">207</li><li style="box-sizing: border-box; padding: 0px 5px;">208</li><li style="box-sizing: border-box; padding: 0px 5px;">209</li><li style="box-sizing: border-box; padding: 0px 5px;">210</li><li style="box-sizing: border-box; padding: 0px 5px;">211</li><li style="box-sizing: border-box; padding: 0px 5px;">212</li><li style="box-sizing: border-box; padding: 0px 5px;">213</li><li style="box-sizing: border-box; padding: 0px 5px;">214</li><li style="box-sizing: border-box; padding: 0px 5px;">215</li><li style="box-sizing: border-box; padding: 0px 5px;">216</li><li style="box-sizing: border-box; padding: 0px 5px;">217</li><li style="box-sizing: border-box; padding: 0px 5px;">218</li><li style="box-sizing: border-box; padding: 0px 5px;">219</li><li style="box-sizing: border-box; padding: 0px 5px;">220</li><li style="box-sizing: border-box; padding: 0px 5px;">221</li><li style="box-sizing: border-box; padding: 0px 5px;">222</li><li style="box-sizing: border-box; padding: 0px 5px;">223</li><li style="box-sizing: border-box; padding: 0px 5px;">224</li><li style="box-sizing: border-box; padding: 0px 5px;">225</li><li style="box-sizing: border-box; padding: 0px 5px;">226</li><li style="box-sizing: border-box; padding: 0px 5px;">227</li><li style="box-sizing: border-box; padding: 0px 5px;">228</li><li style="box-sizing: border-box; padding: 0px 5px;">229</li><li style="box-sizing: border-box; padding: 0px 5px;">230</li><li style="box-sizing: border-box; padding: 0px 5px;">231</li><li style="box-sizing: border-box; padding: 0px 5px;">232</li><li style="box-sizing: border-box; padding: 0px 5px;">233</li><li style="box-sizing: border-box; padding: 0px 5px;">234</li><li style="box-sizing: border-box; padding: 0px 5px;">235</li><li style="box-sizing: border-box; padding: 0px 5px;">236</li><li style="box-sizing: border-box; padding: 0px 5px;">237</li><li style="box-sizing: border-box; padding: 0px 5px;">238</li><li style="box-sizing: border-box; padding: 0px 5px;">239</li><li style="box-sizing: border-box; padding: 0px 5px;">240</li><li style="box-sizing: border-box; padding: 0px 5px;">241</li><li style="box-sizing: border-box; padding: 0px 5px;">242</li><li style="box-sizing: border-box; padding: 0px 5px;">243</li><li style="box-sizing: border-box; padding: 0px 5px;">244</li><li style="box-sizing: border-box; padding: 0px 5px;">245</li><li style="box-sizing: border-box; padding: 0px 5px;">246</li><li style="box-sizing: border-box; padding: 0px 5px;">247</li><li style="box-sizing: border-box; padding: 0px 5px;">248</li><li style="box-sizing: border-box; padding: 0px 5px;">249</li><li style="box-sizing: border-box; padding: 0px 5px;">250</li><li style="box-sizing: border-box; padding: 0px 5px;">251</li><li style="box-sizing: border-box; padding: 0px 5px;">252</li><li style="box-sizing: border-box; padding: 0px 5px;">253</li><li style="box-sizing: border-box; padding: 0px 5px;">254</li><li style="box-sizing: border-box; padding: 0px 5px;">255</li><li style="box-sizing: border-box; padding: 0px 5px;">256</li><li style="box-sizing: border-box; padding: 0px 5px;">257</li><li style="box-sizing: border-box; padding: 0px 5px;">258</li><li style="box-sizing: border-box; padding: 0px 5px;">259</li><li style="box-sizing: border-box; padding: 0px 5px;">260</li></ul>
服务器2:将信息原样返回去
<code class="hljs cpp has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <iostream></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">namespace</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>; <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <cstdio></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <WINSOCK2.H></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <windows.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdio.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma comment(lib, "Ws2_32.lib") <span class="hljs-comment" style="box-sizing: border-box;">// Socket编程需用的动态链接库</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#pragma comment(lib, "Kernel32.lib") <span class="hljs-comment" style="box-sizing: border-box;">// IOCP需要用到的动态链接库</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define PORT 5150</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define DATA_BUFSIZE 8192</span> DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> { OVERLAPPED OVerlapped; WSABUF DATABuf; CHAR Buffer[DATA_BUFSIZE]; DWORD BytesSend, BytesRecv; }PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> { SOCKET Socket; }PER_HANDLE_DATA, *LPPER_HANDLE_DATA; DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* argv[]) { SOCKADDR_IN InternetAddr; SOCKET Listen, Accept; HANDLE CompetionPort; SYSTEM_INFO SystenInfo; LPPER_HANDLE_DATA PerHandleData; LPPER_IO_OPERATION_DATA PerIOData; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i; DWORD RecvBytes; DWORD Flags; DWORD ThreadID; WSADATA wsadata; DWORD Ret; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (Ret = WSAStartup(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x2020</span>, &wsadata) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"WSAStartup failed with error %d/n"</span>, Ret); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//打开一个空的完成端口</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((CompetionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)) == NULL) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"CreateIoCompletionPort failed with error %d/n"</span>, GetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } GetSystemInfo(&SystenInfo); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 开启cpu个数的2倍个的线程</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < SystenInfo.dwNumberOfProcessors * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>; i++) { HANDLE ThreadHandle; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//创建服务器工作线程,并且向线程传送完成端口</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((ThreadHandle = CreateThread(NULL, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, ServerWorkerThread, CompetionPort, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, &ThreadID)) == NULL) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"CreateThread failed with error %d/n"</span>, GetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } CloseHandle(ThreadHandle); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//打开一个服务器socket</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((Listen = WSASocket(AF_INET, SOCK_STREAM, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, NULL, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"WSASocket()failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } InternetAddr.sin_family = AF_INET; InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); InternetAddr.sin_port = htons(PORT); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (bind(Listen, (LPSOCKADDR)&InternetAddr, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(InternetAddr)) == SOCKET_ERROR) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"bind failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (listen(Listen, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) == SOCKET_ERROR) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"listen failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//接收连接并且分发给完成端口</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (TRUE) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((Accept = WSAAccept(Listen, NULL, NULL, NULL, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)) == SOCKET_ERROR) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"WSAAccept failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//创建与套接字相关的套接字信息结构</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(PER_HANDLE_DATA))) == NULL) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"GlobalAlloc failed with error %d/n"</span>, GetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Associate the accepted socket with the original completion port.</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Socket number %d connected/n"</span>, Accept); PerHandleData->Socket = Accept;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//结构中存入接收的套接字</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//与我们的创建的那个完成端口关联起来,将关键项也与指定的一个完成端口关联</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((CreateIoCompletionPort((HANDLE)Accept, CompetionPort, (DWORD)PerHandleData, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)) == NULL) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"CreateIoCompletionPort failed with error%d/n"</span>, GetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建同下面的WSARecv调用相关的IO套接字信息结构体</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((PerIOData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(PER_IO_OPERATION_DATA))) == NULL) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"GlobalAloc failed with error %d/n"</span>, GetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } ZeroMemory(&(PerIOData->OVerlapped), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(OVERLAPPED)); PerIOData->BytesRecv = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; PerIOData->BytesSend = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; PerIOData->DATABuf.len = DATA_BUFSIZE; PerIOData->DATABuf.buf = PerIOData->Buffer; Flags = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (WSARecv(Accept, &(PerIOData->DATABuf), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, &RecvBytes, &Flags, &(PerIOData->OVerlapped), NULL) == SOCKET_ERROR) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (WSAGetLastError() != ERROR_IO_PENDING) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"WSARecv()failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//工作线程</span> DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID) { HANDLE ComplectionPort = (HANDLE)ComlpetionPortID; DWORD BytesTransferred; LPOVERLAPPED Overlapped; LPPER_HANDLE_DATA PerHandleData; LPPER_IO_OPERATION_DATA PerIOData; DWORD SendBytes, RecvBytes; DWORD Flags; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (TRUE) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (GetQueuedCompletionStatus(ComplectionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIOData, INFINITE) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"GetQueuedCompletionStatus failed with error%d/n"</span>, GetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//首先检查套接字上是否发生错误,如果发生了则关闭套接字并且清除同套节字相关的SOCKET_INFORATION 结构体</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (BytesTransferred == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Closing Socket %d/n"</span>, PerHandleData->Socket); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (closesocket(PerHandleData->Socket) == SOCKET_ERROR) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"closesocket failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } GlobalFree(PerHandleData); GlobalFree(PerIOData); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//检查BytesRecv域是否等于0,如果是,说明WSARecv调用刚刚完成,可以用从己完成的WSARecv调用返回的BytesTransferred值更新BytesRecv域</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (PerIOData->BytesRecv == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { PerIOData->BytesRecv = BytesTransferred; PerIOData->BytesSend = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { PerIOData->BytesRecv += BytesTransferred; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (PerIOData->BytesRecv > PerIOData->BytesSend)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//收到数据比发送的多了,就回发出去</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//发布另一个WSASend()请求,因为WSASendi 不能确保发送了请的所有字节,继续WSASend调用直至发送完所有收到的字节</span> ZeroMemory(&(PerIOData->OVerlapped), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(OVERLAPPED)); PerIOData->DATABuf.buf = PerIOData->Buffer + PerIOData->BytesSend; PerIOData->DATABuf.len = PerIOData->BytesRecv - PerIOData->BytesSend; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (WSASend(PerHandleData->Socket, &(PerIOData->DATABuf), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, &SendBytes, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, &(PerIOData->OVerlapped), NULL) == SOCKET_ERROR) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (WSAGetLastError() != ERROR_IO_PENDING) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"WSASend()fialed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { PerIOData->BytesRecv = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//Now that is no more bytes to send post another WSARecv()request</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//现在己经发送完成</span> Flags = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; ZeroMemory(&(PerIOData->OVerlapped), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(OVERLAPPED)); PerIOData->DATABuf.buf = PerIOData->Buffer; PerIOData->DATABuf.len = DATA_BUFSIZE; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (WSARecv(PerHandleData->Socket, &(PerIOData->DATABuf), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, &RecvBytes, &Flags, &(PerIOData->OVerlapped), NULL) == SOCKET_ERROR) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (WSAGetLastError() != ERROR_IO_PENDING) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"WSARecv()failed with error %d/n"</span>, WSAGetLastError()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; } } } } }</code>