C++ SOCKET通信模型(四)IOCP

来源:互联网 发布:rimworld mac版下载 编辑:程序博客网 时间:2024/05/23 01:57

相比IOEvent,IOCP没有事件监听,而是采用线程池管理(其实就是对用户创建的线程的一个分配管理机制,本身并不会创建多余额外的线程)+队列的形式,这个系统队列也就是所谓的完成端口,用于内核与应用层的交互。IOCP没有监听事件数量的限制,没有事件列表为空需要等待的问题,虽然IOEvent没有IOApc里负载均衡问题严重,但还是存在一定负载均衡问题,并且需要自己去做均衡策略,在IOCP里得到完美解决,采用线程间争抢的模式,这是真正意义上的做到了均衡,后面EPOLL我也会用这个策略去做。相比IOApc,上篇所提到的IOApc的5个问题都得到解决。并且可以看出,IOCP更贴近于IOEvent,APC不合理之处实在太多,所以以后也要尽量避免APC的设计使用。

先说说IOCP的设计思路,不知道有没人在看IOEvent的时候曾想过,有没办法绕过事件监听,并且保持大体结构几乎不变。没错,如果能介入wsarecv的设计的话,可以在通知事件那地方,将一个标识放入队列,然后让所有等待队列的线程去争抢这个标识,那么一定是谁闲谁得到这个标识,一直循环,直到队列为空,该线程执行完后又保持空闲状态,并且配合wsarecv这个异步方法,不再需要额外线程,就可以实现整个循环,真的是把线程上的资源用得淋漓尽致。可能说得还比较粗糙,具体的话还需要读者个人去研究体会。


我写的这个代码也是以简洁为前提,所以发送部分都写的同步模式,如果需要用异步发送的话,需要在Client结构中增加个状态标识,并对发送 接收进行区分,一起在Proc中判断并处理。非调试请关闭服务器端输出,不然会执行得很慢


至此,Windows上socket通信模型 先告一段落,附上整个工程下载地址:

https://pan.baidu.com/s/1slt18Jj


// IOCP.cpp: 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include<WinSock2.h>#include<process.h>#include<mutex>#include <deque>#include <map>#pragma comment(lib,"ws2_32.lib")unsigned int WINAPI CreateServ(LPVOID args);unsigned int WINAPI Proc(LPVOID args);using namespace std;int _thread_count;char buf[128];const int _bufLen = 1024;struct Client{WSAOVERLAPPED overlapped;SOCKET s;WSABUF buf;int procId;int id;};HANDLE hCompPort;DWORD dwRecvCount = 0;DWORD nFlag = 0;map<int, Client*> _clients;mutex m;int main(){sprintf_s(buf, "hello client");hCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);_beginthreadex(0, 0, CreateServ, 0, 0, 0);SYSTEM_INFO sysInfo;GetSystemInfo(&sysInfo); _thread_count = sysInfo.dwNumberOfProcessors * 2;for (int i = 0; i < _thread_count; i++) {int* temp = new int(i);_beginthreadex(0, 0, Proc, temp, 0,0);}cin.get();cin.get();return 0;}void release(Client* c){m.lock();_clients.erase(c->id);m.unlock();cout << "release" << endl;closesocket(c->s); //关闭套接字  delete[] c->buf.buf;delete c;}unsigned int WINAPI Proc(LPVOID args){int I = *(int*)args;while (true){Client* c;DWORD dwTransferred;LPWSAOVERLAPPED overlapped;if(GetQueuedCompletionStatus(hCompPort, &dwTransferred, (PULONG_PTR)&c, &overlapped,INFINITE)){if(dwTransferred==0){release(c);continue;}//cout << "proc by:" << I<<endl;//cout << c->buf.buf << endl;memset(c->buf.buf, 0, _bufLen);send(c->s, buf, 128, 0);if (WSARecv(c->s, &c->buf, 1, &dwRecvCount, &nFlag, &c->overlapped, 0) == SOCKET_ERROR){int err = WSAGetLastError();if (err != WSA_IO_PENDING){release(c);}}}else{release(c);}}}unsigned int WINAPI CreateServ(LPVOID args) {srand(time(0));WORD wVersion;WSADATA wsaData;int err;wVersion = MAKEWORD(2, 1);err = WSAStartup(wVersion, &wsaData);if (err != 0) {return 0;}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 1) {WSACleanup();return 0;}SOCKET sockSrv = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);const char chOpt = 1;setsockopt(sockSrv, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(chOpt));int nSendBufLen = 16 * 1024 * 1024;setsockopt(sockSrv, SOL_SOCKET, SO_SNDBUF, (const char*)&nSendBufLen, sizeof(int));SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(ADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6001);::bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));err = listen(sockSrv, SOMAXCONN);if (err == SOCKET_ERROR) {cout << "listen failed" << endl;WSACleanup();return 0;}SOCKADDR_IN remoteAddr;int addrSize = sizeof(remoteAddr);//accept loopwhile (true) {SOCKET s = accept(sockSrv, (SOCKADDR*)&remoteAddr, &addrSize);;Client* c = new Client;memset(c, 0, sizeof(Client));c->s = s;char*  buf = new char[_bufLen];memset(buf, 0, _bufLen);c->buf.buf = buf;c->buf.len = _bufLen;m.lock();int id;do{id = rand() % MAXINT32;} while (_clients.find(id) != _clients.end());_clients.insert(pair<int, Client*>(id, c));c->id = id;m.unlock();if(CreateIoCompletionPort((HANDLE)c->s,hCompPort,(ULONG_PTR)c,0)==0){continue;}if(WSARecv(c->s, &c->buf, 1, &dwRecvCount, &nFlag, &c->overlapped, 0)==SOCKET_ERROR){int err = WSAGetLastError();if(err!=WSA_IO_PENDING){release(c);}}}return 0;}



阅读全文
0 0
原创粉丝点击