当前位置: 首页 > news >正文

延庆青岛网站建设广西网站建设哪家好

延庆青岛网站建设,广西网站建设哪家好,海淀网站制作服务公司,怎么制作图片文件通过重叠I/O理解IOCP 本章的IOCP#xff08;Input Output CompletionPort#xff0c;输入输出完成端口#xff09;服务器端模型是很多Windows程序员关注的焦点。各位若急于求成而跳过了第21章的内容#xff0c;建议大家最好回顾一下。因为第21章和第22章介绍了本章的背景知…通过重叠I/O理解IOCP 本章的IOCPInput Output CompletionPort输入输出完成端口服务器端模型是很多Windows程序员关注的焦点。各位若急于求成而跳过了第21章的内容建议大家最好回顾一下。因为第21章和第22章介绍了本章的背景知识而且关于IOCP的内容实际上是从第22章开始的。 实现非阻塞模式的套接字 第22章中只介绍了执行重叠I/O的Sender和Receiver但还未利用该模型实现过服务器端。因此我们先利用重叠I/O模型实现回声服务器喘。首先介绍创建非阻塞模式套接字的方法。我们曾在第17章创建过非阻塞模式的套接字与之类似在Windows中通过如下函数调用将套接字属性改为非阻塞模式。 SOCKET hLisnSock; int mode1; ..... hListSockWSASocket(PF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);//创建重叠IO ioctlsocket(hLisnSock,FIONBIO,mode);//设定套接字为非阻塞属性 ..... 上述代码中调用的ioctlsocket函数负责控制套接字I/O方式,其调用具有如下含义:“将hLisnSock句柄引用的套接字I/O模式(FIONBIO)改为变量mode中指定的形式。” 也就是说FIONBIO是用于更改套接字I/O模式的选项该函数的第三个参数中传入的变量中若存有0则说明套接字是阻塞模式的如果存有非0值则说明已将套接字模式改为非阻塞模式。改为非阻塞模式后除了以非阻塞模式进行I/O外还具有如下特点。 □如果在没有客户端连接请求的状态下调用accept函数将直接返回INVALID_SOCKET。调用WSAGetLastError函数时返回WSAEWOULDBLOCK。 □调用accept函数时创建的套接字同样具有非阻塞属性。 因此针对非阻塞套接字调用accept函数并返回INVALID_SOCKET时应该通WSAGetLastError 函数确认返回INVALID_SOCKET的理由再进行适当处理。 以纯重叠I/O方式实现回声服务器端 要想实现基于重叠I/O的服务器端必须具备非阻塞套接字所以先介绍了其创建方法。实 际上因为有IOCP模型所以很少有人只用重叠I/O实现服务器端。但我认为“为了正确理解IOCP应当尝试用纯重叠I/O方式实现服务器端。” 即使坚持不用IOCP也应具备仅用重叠I/O方式实现类似IOCP的服务器端的能力。这样就可以在其他操作系统平台实现类似IOCP方式的服务器端而且不会因IOCP的限制而忽略服务器端 功能的实现。 下面用纯重叠I/O模型实现回声服务器端由于代码量较大我们分3个部分学习。 #includestdio.h #includestdlib.h #includewinsock2.h #define BUF_SIZE 1024void CALLBACK ReadCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD); void CALLBACK WriteCompRoutine(DWORD,DWORD, LPWSAOVERLAPPED, DWORD); void ErrorHandling(char *message);typedef struct{SOCKET hClntSock;char buf[BUF_SIZE];WSABUF wsaBuf; } PER_IO_DATA, *LPPER IO_DATA; 该结构体中的信息足够进行数据交换下列代码将介绍该结构体的填充及使用方法。 int main(int argc, char* argv[]){WSADATA wsaData;SOCKET hLisnSock, hRecvSock;SOCKADDR_IN lisnAdr, recvAdr;LPWSAOVERLAPPED lpOvLp;DWORD recvBytes;LPPER_IO_DATA hbInfo;int mode1, recvAdrsz, flagInfo0;if(argc!2) {printf(Usage: %s port\n,argv[0]);exit(1);}if(WSAStartup(MAKEWORD(2,2), wsaData)!0)ErrorHandling(WSAStartup() error!);hLisnSockWSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);ioctlsocket(hLisnSock, FIONBIO, mode);memset(lisnAdr,0, sizeof(lisnAdr));lisnAdr.sin_familyAF_INET;lisnAdr.sin_addr.s_addrhtonl(INADDR_ANY);lisnAdr.sin_porthtons(atoi(argv[1]));if(bind(hLisnSock(SOCKADDR*)lisnAdr, sizeof(lisnAdr))SOCKET_ERROR)ErrorHandling(bind() error);if(listen(hLisnSock,5)SOCKET_ERROR)ErrorHandling(listen() error);recvAdrSzsizeof(recvAdr);while(1){SleepEx(100,TRUE);hRecvSockaccept(hLisnsock,(SOCKADDR*)recvAdr,recvAdrSz);if(hRecvSockINVALID_SOCKET){if(WSAGetLastError()WSAEWOULDBLOCK)continue;else ErrorHandling(accept() error);}puts(Client connected.....);lpOvLp(LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));memset(lpOvLp, 0, sizeof(WSAOVERLAPPED));hbInfo(LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA)); hbInfo-hClntSock(DWORD)hRecvSock;(hbInfo-wsaBuf).bufhbInfo-buf;(hbInfo-wsaBuf).lenBUF_SIZE;lpOvLp-hEvent(HANDLE)hbInfo;WSARecv(hRecvSock,(hbInfo-wsaBuf),1,recvBytes, flagInfo, lpOvLP, ReadcompRoutine);}closesocket(hRecvSock);closesocket(hLisnSock);WSACleanup();return 0;} 有几点需要注意: 第46、47行申请重叠I/O中需要使用的结构体变量的内存空间并初始化。之所以在循环 内部申请WSAOVERLAPPED结构体空间是因为每个客户端都需要独立的WSAOVERLAPPED结构体变量。 第54行WSAOVERLAPPED结构体变量的hEvent成员中将写入第49行分配过空间的变量 地址值。基于Completion Routine函数的重叠I/O中不需要事件对象因此hEvent中可以写入其他信息。 第55行调用WSARecv函数时将ReadCompRoutine函数指定为Completion Routine。其 中第六个参数WSAOVERLAPPED结构体变量地址值将传递到Completion Routine的第三个参数因此Completion Routine函数内可以访问完成I/O的套接字句柄和缓冲。另外为了运行Completion Routine函数第35行循环调用SleepEx函数。 最后介绍两个Completion Routine函数。实际的回声服务是通过这两个函数完成的。 void CALLBACK ReadCompRoutine(DWORD dwError, DWORD szRecvBytes, LPWSAOVERLAPPED ipOverlapped, DWORD flags){LPPER_IO_DATA hbInfo(LPPER_IO_DATA)(1pOverlapped-hEvent);hSockhbInfo-hClntsock;LPWSABUF bufInfo(hbInfo-wsaBuf);DWORD sentBytes;if(szRecvBytes0){//如果接收到了EOF那么则关闭套接字以及释放对应的空间closesocket(hSock);free(lpoverlapped-hEvent);free(lpoverlapped); puts(Client disconnected.....);}else{//如果不为零那么一定有需要回声的内容bufInfo-lenszRecvBytes;WSASend(hSock,bufInfo,1, sentBytes, 0, lpoverlapped, WriteCompRoutine);} }void CALLBACK WriteCompRoutine(DWORD dwError, DWORD szSendBytes, LPWSAOVERLAPPED lpoverlapped, DWORD flags){LPPER_IO_DATA hbInfO(LPPER_IO_DATA)(lpOverlapped-hEvent);SOCKET hSockhbInfo-hClntSock;LPWSABUF bufInfo(hbInfo-wsaBuf);DWORD recvBytes;int flagInfo0;WSARecv(hSock,bufInfo,1,recvBytes,flagInfo, lpoverlapped, ReadCompRoutine);//发送后默认等待再次回声 }void ErrorHandling(char *message){fputs(message, stderr);fputc(\n,stderr);exit(1); } 有几个注意点: 第4~6行提取完成输入的套接字句柄和缓冲信息因为WSAOVERLAPPED结构体变量 的hEvent成员中保存了PER_IO_DATA结构体变量地址值。 第9行变量szRecvBytes的值为0就意味着收到了EOF因此需要进行相应处理。 第17、18行将WriteCompRoutine函数指定为Completion Routine同时调用WSASend 函数。程序通过该语句向客户端发送回声消息。 第22、30行发送回声消息后调用该函数。但需要再次接收数据所以执行第30行的函数 上述示例的工作原理整理如下。 □有新的客户端连接时调用WSARecv函数并以非阻塞模式接收数据接收完成后调用 ReadCompRoutine函数。 □调用ReadCompRoutine函数后调用WSASend函数并以非阻塞模式发送数据发送完成后 调用WriteCompRoutine函数。 □此时调用的WriteCompRoutine雨数将再次调用WSARecv函数并以非阻塞模式等待接收 数据。 通过交替调用ReadCompRoutine函数和WriteCompRoutine函数反复执行数据的接收和发送操作。另外每次增加1个客户端都会定义PERIO_DATA结构体以便将新创建的套接字句柄和缓冲信息传递给ReadCompRoutine函数和WriteCompRoutine函数。同时将该结构体地址值写人WSAOVERLAPPED结构体成员hEvent并传递给Completion Routine函数。这非常重要可概括如下: “使用WSAOVERLAPPED结构体成员hEvent向完成I/O时自动调用的Completion Routine函数内部传递客户端信息套接字和缓冲)。 接下来需要验证运行结果先要编写回声客户端因为使用第4章的回声客户端会无法得到预想的结果。 重新实现客户端 其实第4章实现并使用至今的回声客户端存在一些问题关于这些问题及解决方案已在第5章进行了充分讲解。虽然在目前为止的各种模型的服务器端中使用稍有缺陷的回声客户端也不会引起太大问题但本章的回声服务器端则不同。因此需要按照第5章的提示解决客户端存在的问题并结合改进后的客户端运行本章服务器端。之前已介绍过解决方法故只给出代码。 #include “头声明与之前示例一致。“ #define BUF SIZE 1024 void ErrorHandling(char *message);int main(int argc, char *argv[]){WSADATA wsaData;SOCKET hSocket;SOCKADDR_IN servAdr;char message[BUF_SIZE];int strlen, readLen;if(argc!3){printf(Usage: %s IP port\n, argv[0]);exit(1);}if(WSAStartup(MAKEWORD(22), wsaData)!0)ErrorHandling(WSAStartup() error!);hSocketsocket(PF_INET,SOCK_STREAM, 0);if(hSocketINVALID_SOCKET)ErrorHandling(socket() error);memset(servAdr, 0, sizeof(servAdr));servAdr.sin_familyAF_INET;servAdr.sin_addr.s _addrinet_addr(argv[1]);servAdr.sin_porthtons(atoi(argv[2]));if(connect(hSocket,(SOCKADDR*)servAdr, sizeof(servAdr))SOCKET_ERROR)ErrorHandling(connect()error!);elseputs(Connected......);while(1){fputs(Input message(Q to quit):, stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message,q\n)||!strcmp(message,Q\n))break;strLenstrlen(message);send(hSocket, message, strLen, 0);readLen0;while(1){readLenrecv(hSocket,message[readlen], BUF_SIZE-1-readLen,0);if(readLenstrLen)break;}message[strLen]0;printf(Message from server: %s, message);}closesocket(hSocket);WSACleanup();return 0; }void ErrorHandling(char *message){ //与其他Windows相关示例一致故省略。 } 上述代码第44行的循环语句考虑到TCP的传输特性而重复调用了recv函数直至接收完所有数据。将上述客户端结合之前的回声服务器端运行可以得到正确的运行结果具体结果与一般的回声服务器端/客户端没有区别故省略。 从重叠I/O模型到IOCP模型 下面分析重叠I/O模型回声服务器端的缺点。 “重复调用非阻塞模式的accept函数和以进入alertable wait状态为目的的SleepEx函数将影响性能 如果正确理解了之前的示例应该不难发现这一点。既不能为了处理连接请求而只调用accept函数也不能为了Completion Routine而只调用SleepEx函数因此轮流调用了非阻塞模式的accept函数和SleepEx函数设置较短的超时时间)。这个恰恰是影响性能的代码结构。 我也不知该如何弥补这一缺点这属于重叠I/O结构固有的缺陷但可以考虑如下方法 “让main线程在main函数内部调用accept函数再单独创建1个线程负责客户端I/O。” 其实这就是IOCP中采用的服务器端模型。换言之IOCP将创建专用的I/O线程、该线程负责 与所有客户端进行I/O。 分阶段实现IOCP程序 本节我们编写最后一种服务器模型IOCP比阅读代码更重要的是理解IOCP本身。 创建“完成端口” IOCP中已完成的I/O信息将注册到完成端口对象Completion Port简称CP对象但这个过 程并非单纯的注册首先需要经过如下请求过程“该套接字的I/O完成时请把状态信息注册到指定CP对象。 该过程称为“套接字和CP对象之间的连接请求”。因此为了实现基于IOCP模型的服务器端 需要做如下2项工作。 □创建完成端口对象。 □建立完成端口对象和套接字之间的联系。 此时的套接字必须被赋予重叠属性。上述2项工作可以通过1个函数完成但为了创建CP对 象先介绍如下函数。 #include windows.h HANDLE CreateIoCompletionport(HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR Completionkey,DWORD NumberofConcurrentThreads); //成功时返回CP对象句柄失败时返回NULL。FileHandle //创建CP对象时传递INVALID_HANDLE_VALUE。ExistingCompletionPort //创建CP对象时传递NULL。CompletionKey //创建CP对象时传递0。NumberOfConcurrentThreads//分配给CP对象的用于处理I/O的线程数。例如该参数为2时说明分配 //给CP对象的可以同时运行的线程数最多为2个如果该参数为0,系统中 //CPU个数就是可同时运行的最大线程数。 以创建CP对象为目的调用上述函数时只有最后一个参数才真正具有含义。可以用如下代码段将分配给CP对象的用于处理IO的线程数指定为2。 HANDLE hCpObject; ..... hCpObject CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,2); 连接完成端口对象和套接字 既然有了CP对象接下来就要将该对象连接到套接字只有这样才能使已完成的套接字I/O信息注册到CP对象。下面以建立连接为目的再次介绍CreateCompletionPort函数。 #include windows.h HANDLE CreateIoCompletionPort(HANDLE FileHandle, HANDLE ExistingCompletionport, ULONG_PTR Completionkey,DWORD NumberofConcurrentThreads); //成功时返回CP对象句柄失败时返回NULL。FileHandle //要连接到CP对象的套接字句柄。ExistingCompletionPort //要连接套接字的CP对象句柄。CompletionKey //传递已完成I/O相关信息关于该参数将在稍后介绍的GetQueued//CompletionStatus函数中共同讨论。NumberOfConcurrentThreads //无论传递何值只要该函数的第二个参数非NULL就会忽略。 上述函数的第二种功能就是将FileHandle句柄指向的套接字和ExistingCompletionPort指向的 CP对象相连。该函数的调用方式如下。 HANDLE hCpObject; SOCKET hSock; ...... CreateIoCompletionPort((HANDLE)hSock,hCpObject,(DWORD)ioInfo,0); 调用CreateIoCompletionPort函数后只要针对hSock的I/O完成相关信息就将注册到hCpObject指向的CP对象。 确认完成端口已完成的I/O和线程的I/O处理 我们已经掌握了CP对象的创建及其与套接字建立连接的方法接下来就要学习如何确认CP 中注册的已完成的IO。完成该功能的函数如下。 #include windows.h BOOL GetQueuedCompletionStatus(HANDLE CompletionPort, LPDWORD lpNumberOfBytes,PULONG_PTR lpCompletionKey,LPOVERLAPPED * lpoverlapped, DWORD dwMilliseconds); //成功时返回TRUE失败时返回FALSE.CompletionPort //注册有已完成I/O信息的CP对象句柄IpNumberOfBytes //用于保存I/O过程中传输的数据大小的变量地址值。IpCompletionKey //用于保存CreateIoCompletionPort函数的第三个参数值的变量地址值。IpOverlapped //用于保存调用WSASend、WSARecv函数时传递的OVERLAPPED结构体地址的变量地址 //值。dwMilliseconds //超时信息超过该指定时间后将返回FALSE并跳出函数。传递INFINITE时程序//将阻塞直到已完成I/O信息写入CP对象。 虽然只介绍了2个IOCP相关函数但依然有些复杂特别是上述函数的第三个和第四个参数更是如此。其实这2个参数主要是为了获取需要的信息而设置的下面介绍这2种信息的含义。 “通过GetQueuedCompletionStatus函数的第三个参数得到的是以连接套接字和CP对象为目的而调用的CreateloCompletionPort函数的第三个参数值。” “通过GetQueueCompletionStatus函数的第四个参数得到的是调用WSASend、WSARecv函数时传入的WSAOVERLAPPED结构体变量地址值。” 各位需要通过示例理解这2个参数的使用方法。接下来讨论其调用主体究竟由谁何时调用上述函数比较合理呢如各位所料应该由处理IOCP中已完成I/O的线程调用。可能有人又有疑问:“那I/O如何分配给线程呢 如前所述IOCP中将创建全职I/O线程由该线程针对所有客户端进行I/O。而且CreateloCompletionPort函数中也有参数用于指定分配给CP对象的最大线程数所以各位或许会有如下疑问“是否自动创建线程并处理I/O” 当然不是应该由程序员自行创建调用WSASend、WSARecv等I/O函数的线程只是该线程为了确认I/O的完成会调用GetQueuedCompletionStatus函数。虽然任何线程都能调用GetQueuedCompletionStatus函数但实际得到I/O完成信息的线程数不会超过调用CreateIoCompletionPort函数时指定的最大线程数。 以上就是IOCP服务器端实现时需要的全部函数及其理论说明下面通过源代码理解程序的整体结构。 实现基于IOCP的回声服务器端 虽然介绍了IOCP相关的理论知识但离开示例很难真正掌握IOCP的使用方法。因此我将介绍便于理解和运用的(极为普通的)基于IOCP的回声服务器端。首先给出IOCP回声服务器端的main函数之前的部分。 #includestdio.h #includestdlib.h #includeprocess.h #includewinsock2.h #includewindows.h#define BUF SIZE 100 #define READ 3 #define WRITE 5typedef struct{SOCKET hClntsock;SOCKADDR_IN clntAdr; } PER_HANDLE_DATA, *LPPER_HANDLE_DATA;typedef struct{OVERLAPPED overlapped;WSABUF wsaBuf;char buffer[BUF_SIZE];int rwMode; } PER_IO_DATA, *LPPER_IO_DATA;DWORD WINAPI EchoThreadMain(LPVOID CompletionPortIo); void ErrorHandling(char *message); 第11行:保存与客户端相连套接字的结构体。 第17行:将I/O中使用的缓冲和重叠I/O中需要的OVERLAPPED结构体变量封装到同一结构 体中进行定义。 接下来介绍main函数部分。 int main(int argc, char* argv[]){WSADATA wsaData;HANDLE hComPort;SYSTEM_INFO sysInfo;LPPER_IO_DATA ioInfo; LPPER_HANDLE_DATA handleInfo;SOCKET hServSock;SOCKADDR_IN servAdr;int recvBytes, i, flags0;if(WSAStartup(MAKEWORD(2,2),wsaData)!0)ErrorHandling(WSAStartup() error!);hComPortCreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0, 0);//创建CP对象GetSystemInfo(sysInfo);//获得当前系统的信息for(i0; isysInfo.dwNumberofprocessors;i)_beginthreadex(NULL,0,EchoThreadMain,(LPVOID)hComport,0,NULL);hServSockWSASocket(AF_INETSOCK_STREAM,0NULL, 0, WSA_FLAG_OVERLAPPED);memset(servAdr, 0, sizeof(servAdr));servAdr.sin_familyAF_INET;servAdr.sin_addr.s_addrhtonl(INADDR_ANY);servAdr.sin_porthtons(atoi(argv[1]));bind(hServSock,(SOCKADDR*)servAdr,sizeof(servAdr));listen(hServSock,5);while(1){SOCKET hClntSock;SOCKADDR_IN clntAdr;int addrLensizeof(clntAdr);hClntSockaccept(hServSock,(SOCKADDR*)clntAdr,addrLen);handleInfo(LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));handleInfo-hClntSockhClntSock;memcpy((handleInfo-clntAdr),clntAdr, addrLen);CreateIoCompletionPort((HANDLE)hCIntSock,hComport,(DWORD)handleInfo,0)//建立连接ioInfo(LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));memset((ioInfo-overlapped), 0, sizeof(OVERLAPPED));ioInfo-wsaBuf.lenBUF_SIZE;ioInfo-wsaBuf.bufioInfo-buffer;ioInfo-rwModeREAD;WSARecv(handleInfo-hClntSock,(ioInfo-wsaBuf),1,recvBytes,flags,(ioInfo- overlapped),NULL);} return 0; } 有几个注意点: 第36~38行动态分配PER_HANOLE_DATA结构体并写入客户端相连套接字和客户端地 址信息。 第40行连接第15行创建的CP对象和第35行创建的套接字。针对这套接字的重叠I/O完成 时已完成信息将写入连接的CP对象这会引起GetQueue...函数的返回。请注意观察第三个参数的值。该值是第36~38行中声明开初始化的结构体变量地址值它同样是在GetQueued..函数返回时得到的。 第42行动态分配PER_IO_DATA结构体变量空间。相当于同时准备了WSARecv函数中需 要的OVERLAPPED结构体变量、WSABUF结构体变量及缓冲。 第46行IOCP本身不会帮我们区分输入完成和输出完成的状态。无论输入还是输出只 通知完成I/O的状态因此需要通过额外的变量区分这2种I/O。PER_IO_DATA结构体中的rwMode就用于完成该功能。 第47行WSARecv函数的第七个参数为OVERLAPPED结构体变量地址值该值可以在 GetQueue...函数返回时得到。但结构体变量地址值与第一个成员的地址值相同也就相当于传入了PER_IO_DATA结构体变量地址值。 最后给出线程main函数则部分代码需要结合之前的main函数进行分析。 DWORD WINAPI EchoThreadMain(LPVOID pComPort){HANDLE hComPort(HANDLE)pComPort;SOCKET sock;DWORD bytesTrans;LPPER_HANDLE_DATA handleInfo;LPPER_IO_DATA ioInfo;DWORD flags0;while(1){GetQueuedCompletionStatus(hComport,bytesTrans, (LPDWORD)handletnfo(LPOVERLAPPED*)ioInfo, INFINITE);sockhandleInfo-hclntsock,if(ioInfo-rwModeREAD){puts(message received!);if(bytesTrans0){//传输EOF时closesocket(sock);free(handleInfo);free(ioInfo);continue;}memset((ioInfo-overlapped), 0,sizeof(OVERLAPPED));ioInfo-wsaBuf.lenbytesTrans;ioInfo-rwModeWRITE;WSASend(sock,(ioInfo-wsaBuf),1,NULL, 0, (ioInfo-overlapped),NULL);ioInfo(LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));memset((ioInfo-overlapped),0, sizeof(OVERLAPPED));ioInfo-wsaBuf.lenBUF_SIZE;ioInfo-wsaBuf.bufioInfo-buffer;ioInfo-rwModeREAD;WSARecv(sock,(ioInfo-wsaBuf),1,NULL, flags,(ioInfo-overlapped),NULL);}else{puts(message sent!);free(ioInfo);}}return 0;void ErrorHandling(char *message){fputs(message, stderr);fputc(\n, stderr);exit(1); } 第12行GetQueued..函数在I/O完成且己注册相关信息时返回因为最后一个参数为 INFINITE。另外返回时可以通过第三个和第四个参数得到之前提过的2个信 息。 第16行指针iolnfo中保存的既是OVERLAPPED结构体变量地址值也是PER_IO_DATA 结构体变量地址值。因此可以通过检查rwMode成员中的值判断是输入完成还是输出完成。 第26~30行将服务器端收到的消息发送给客户端。 第32~38行再次发送消息后接收客户端消息。 第40行完成的I/O为输出时执行的else区域。 IOCP性能更优的原因 盲目地认为“因为是IOCP所以性能更好”的想法并不可取。之前已介绍了Linux和Windows下多种服务器端模型各位应该可以分析出它们在性能上的优势。将其在代码级别与select进行对比可以发现如下特点。 1.因为是非阻塞模式的I/O所以不会由I/O引发延迟 2.查找已完成I/O时无需添加循环 3.无需将作为I/O对象的套接字句柄保存到数组进行管理 4.可以调整处理I/O的线程数所以可在实验数据的基础上选用合适的线程数。 仅凭这些特点也能判断IOCP属于高性能模型IOCP是Windows特有的功能所以很大程度上要归功于操作系统。无需怀疑它提供的性能我认为IOCP和Linux的epoll都是非常优秀的服务器端模型。
http://www.sadfv.cn/news/124699/

相关文章:

  • 网站建设引流刘贺稳1wordpress必备
  • 17网站一起做网店广州短视频推广营销
  • 网页加入信任站点小米发布会汽车
  • 悠悠我心个人网站模板外贸类网站建设
  • 淘宝网站建设的详细策划网站开发需求大吗
  • wordpress网站变灰网站底部给网站地图做链接
  • 个人信息网站htmlflash网站代码下载
  • 六站合一的优势綦江网站建设
  • 福州网站建设哪家好石家庄市环保局网站建设项目备案系统
  • 做网站是用源码还是模版中小公司做网站
  • 漳州建设银行网站德兴市网站建设服务公司
  • 佛山骏域网站建设免费空间 个人网站 google广告联盟
  • 茶叶网站模板下载网站seo优化步骤
  • 网站域名后缀代表什么意思关于网站开发的外文翻译
  • 小游戏网站开发需要什么技术西安企业seo
  • 莒县做网站和微信企业网站首页布局尺寸
  • 长沙快速建站模板东莞网站设计公司哪家好
  • 个人网站建设的目的域名做网站自己的电脑
  • 网站网上商城建设固安建站公司
  • 如何提高网站点击量软件公司网站设计与制作
  • 查竣工验收报告的网站wordpress好看的自定义页面模版
  • 可以用什么网站做mc官方wordpress产品页布局
  • 用dw做的网页怎么连到网站上网站不收录
  • 网站建设哪家好 需要多少钱学校网站建设模板
  • 软件工程师招聘成都网站搭建优化推广
  • 中国建设业管理协会网站vs2015可以做网站么
  • 南充公司网站建设做网站别人输账号代码
  • 网新科技做网站怎么样wordpress怎么不缩略图
  • 东莞手机网站做手机网站用什么程序好
  • 关于申请网站建设维护经费装潢设计培训班