C++ SOCKET通信模型(二)IOEvent

来源:互联网 发布:java开发包装2年经验 编辑:程序博客网 时间:2024/06/04 20:04

本系列我准备做一个完整的研究,包含Windows的IOCP IOEvent,linux的poll 和 epoll,上篇已经说了非阻塞IO衍化的select多路复用IO,由于windows和linux都差不多,就不再多说select模型了。那么还是先从windows开始吧,这篇主要看下IOEvent。虽然windows作为服务器没有linux那么强,但还是不得不佩服微软的设计思路,这种模型看起来没有任何多余的损耗,可惜也就是因为微软帮开发人员做得太细,导致了一些问题,具体的以后的文章会说到。IOEvent 用的是Overlapped IO模型,Overlapped IO不仅仅用于网络通信中,包括文件的读写都可能用到。使用起来也比较简单,仅需要将fd buf overlapped(event) 这4者绑在一起,由内核完成数据的收发,并通过event 通知应用层,应用层再进行数据操作已经完成后的操作,不需要多余的内存拷贝,数据已经在指定的buf上了。比较可惜的是,由于操作系统的机制问题,WSAWaitForMultipleEvents 仅仅能监听64个事件,就是说1个线程最多同时处理64个socket,不过这也不是什么问题,多建立几个线程即可,没有其他人说的那么夸张,顶多也就多了一些额外的上下文切换,具体就一起来看看代码吧

server:

// IOEvent.cpp: 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include<WinSock2.h>#include<process.h>#include<list>#include<mutex>#include <atomic>#include <vector>#pragma comment(lib,"ws2_32.lib")unsigned int WINAPI CreateServ(LPVOID args);unsigned int WINAPI Proc(LPVOID args);using namespace std;const int _thread_count = 32;const int _bufLen = 1024;struct Client{SOCKET s;WSABUF buf;WSAOVERLAPPED overlapped;};DWORD dwRecvCount = 0;DWORD nFlag = 0;int _nIndex[_thread_count]={0};WSAEVENT _eventList[_thread_count][64];Client* _clients[_thread_count][64]={0};mutex m[_thread_count];int main(){_beginthreadex(0, 0, CreateServ, 0, 0, 0);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;}unsigned int WINAPI Proc(LPVOID args){int* I = (int*)args;int nIndex = 0;while (true){while (_nIndex[*I] == 0){Sleep(500);}nIndex = WSAWaitForMultipleEvents(_nIndex[*I], _eventList[*I], false, WSA_INFINITE,false);if (nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)continue;nIndex = nIndex - WSA_WAIT_EVENT_0;cout << "proc by:" << *I << endl;list<int> removeList;for(int i=nIndex;i<64;i++){if(_clients[i]==0){break;}int val=WSAWaitForMultipleEvents(1, &_eventList[*I][i], true, 0, false);if (val == WSA_WAIT_FAILED || val == WSA_WAIT_TIMEOUT)continue;WSAResetEvent(_eventList[*I][i]);DWORD retval;WSAGetOverlappedResult(_clients[*I][i]->s, &_clients[*I][i]->overlapped, &retval, true, &nFlag);if (retval == 0){removeList.push_back(i);}else{//cout << _clients[*I][i]->buf.buf << endl;memset(_clients[*I][i]->buf.buf, 0, _bufLen);WSARecv(_clients[*I][i]->s, &_clients[*I][i]->buf, 1, &dwRecvCount, &nFlag, &_clients[*I][i]->overlapped, 0);char buf[128];sprintf_s(buf, "hello client");send(_clients[*I][i]->s, buf, 128, 0);}}removeList.sort([](const int a1,const int a2) {return a1 > a2;});m[*I].lock();for(auto iter=removeList.begin();iter!=removeList.end();++iter){cout << "release" << endl;Client* c = _clients[*I][*iter];c->overlapped.hEvent = 0;WSACloseEvent(_eventList[*I][*iter]);closesocket(c->s);if (_nIndex[*I] > 1){_clients[*I][*iter] = _clients[*I][_nIndex[*I] - 1];_clients[*I][_nIndex[*I] - 1] = 0;_eventList[*I][*iter] = _eventList[*I][_nIndex[*I] - 1];_eventList[*I][_nIndex[*I] - 1] = 0;}else{_eventList[*I][*iter] = 0;_clients[*I][_nIndex[*I]-1] = 0;}delete[] c->buf.buf;delete c;_nIndex[*I] -= 1;}m[*I].unlock();}}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, 100);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;c->s = s;char*  buf = new char[_bufLen];memset(buf, 0, _bufLen);c->buf.buf = buf;c->buf.len = _bufLen;int i;do{i = rand() % _thread_count;} while (_nIndex[i] >= 64);m[i].lock();_clients[i][_nIndex[i]] = c;_eventList[i][_nIndex[i]] = WSACreateEvent();c->overlapped.hEvent = _eventList[i][_nIndex[i]];WSARecv(s, &c->buf, 1, &dwRecvCount,&nFlag, &c->overlapped,0);_nIndex[i] = _nIndex[i] + 1;m[i].unlock();}}

client:

与 C++ SOCKET通信模型(一) 相同,这里就不再重复粘贴出来了



原创粉丝点击