C++ SOCKET通信模型(四)IOCP
2017-08-29 17:23
295 查看
相比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的设计思路,不知道有没人在看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 loop while (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; }
相关文章推荐
- C++ SOCKET通信模型(二)IOEvent
- C++ SOCKET通信模型(一)select
- C++ SOCKET通信模型(五)poll
- C++ SOCKET通信模型(三)IOApc
- socket通信网络模型 ——Epoll、IOCP模型详解以及与select、kqueue等常见模型的区别特点
- C++ SOCKET通信模型(六)同步epoll
- 完成端口封装(修复Windows 网络与通信程序设计 可伸缩IOCP模型的bug)
- C++ SOCKET通信模型(七)异步epoll
- Twisted的网络通信模型
- winsock的阻塞和非阻塞通信模型
- 浅谈云巴实时通信的编程模型
- 系统间通信(3)——IO通信模型和JAVA实践 上篇
- Android中ActivityManagerService与应用程序(客户端)通信模型分析
- 系统间通信(5)——IO通信模型和JAVA实践 下篇
- 【链接】Windows IOCP 模型开发资源
- Android线程通信模型-AsyncTask类
- Android中ActivityManagerService与应用程序(客户端)通信模型分析
- socket编程 -- epoll模型服务端/客户端通信的实现
- C++ Socket通信总结(附C++实现)
- IOCP模型与网络编程