完成端口IOCP与AcceptEx, NO MFC, JUST win api
2014-10-25 22:17
309 查看
参考:《windows网络编程》、度娘、谷歌、还有一篇博客和它的源码/article/2112873.html,感谢PiggyXP,不过我的代码有更好的可读性,感谢broadcom的嵌入式C++系统带给我的编程经验,不过流程基本相似,可以关注一些细节
HttpServer\targetver.h:
Windows platform header,系统生成的
HttpServer\stdafx.h:
系统头文件和一些通用define
HttpServer\stdafx.cpp :
预编译stdafx.h使用的源文件,无内容
HttpServer\Start.cpp:
console程序入口,目前不必实现stop,因为结束console主线程,该进程的其余线程也将退出
TODO:做界面的时候再实现stop和restart功能,可能需要使用PostQueuedCompletionStatus函数来通知worker线程退出
HttpServer\IOCPServer.h:
HttpServer\IOCPServer.cpp:
完成端口模型的TCP server
HttpServer\SocketHandle.h:
HttpServer\SocketHandle.cpp: 对应于每一个socket的handle类定义,一个socket
handle可持有多个IO数据组成的list
HttpServer\PerIOData.h:
HttpServer\PerIOData.cpp:
单个IO数据,包含overlapped结构,而且该结构必须在类内存空间的最开始
流程图:
源码如下,其他的不细说了,看注释吧,不过是英文的
,英文语法就别深究了:
HttpServer\stdafx.h:
HttpServer\Start.cpp
HttpServer\IOCPServer.h:
HttpServer\IOCPServer.cpp:
HttpServer\SocketHandle.h:
HttpServer\SocketHandle.cpp:
HttpServer\PerIOData.h:
HttpServer\PerIOData.cpp:
HttpServer\targetver.h:
Windows platform header,系统生成的
HttpServer\stdafx.h:
系统头文件和一些通用define
HttpServer\stdafx.cpp :
预编译stdafx.h使用的源文件,无内容
HttpServer\Start.cpp:
console程序入口,目前不必实现stop,因为结束console主线程,该进程的其余线程也将退出
TODO:做界面的时候再实现stop和restart功能,可能需要使用PostQueuedCompletionStatus函数来通知worker线程退出
HttpServer\IOCPServer.h:
HttpServer\IOCPServer.cpp:
完成端口模型的TCP server
HttpServer\SocketHandle.h:
HttpServer\SocketHandle.cpp: 对应于每一个socket的handle类定义,一个socket
handle可持有多个IO数据组成的list
HttpServer\PerIOData.h:
HttpServer\PerIOData.cpp:
单个IO数据,包含overlapped结构,而且该结构必须在类内存空间的最开始
流程图:
源码如下,其他的不细说了,看注释吧,不过是英文的
,英文语法就别深究了:
HttpServer\stdafx.h:
// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include "targetver.h" #include <cstdio> #include <cassert> #include <tchar.h> #include <string.h> // TODO: reference additional headers your program requires here // win header and lib #include <winsock2.h> #include <MSWSock.h> #pragma comment(lib,"ws2_32.lib") #include <list> using namespace std; #define IOCP_DBUG(format, ...) printf("%s,%d: " format, __FUNCTION__, __LINE__, ##__VA_ARGS__);
HttpServer\Start.cpp
#include "stdafx.h" #include "IOCPServer.h" int _tmain(int argc, _TCHAR* argv[]) { IOCP_DBUG("enter Start\n"); IOCPServer *iocpserver = new IOCPServer(); iocpserver->Start(); while(TRUE) { Sleep(5000); } delete iocpserver; return 0; }
HttpServer\IOCPServer.h:
#pragma once #include "stdafx.h" #include "PerIOData.h" #include "SocketHandle.h" // this is IOCPServer which use IOCP // has no GUI, we provide two public function to call // two public function: start() and stop() // you can write new interface class IOCPServer { public: IOCPServer(void); virtual ~IOCPServer(void); public: bool Start(void); bool Stop(void); // self member hold in whole life of the class object //so we have no need to tranfer these in function parameters private: HANDLE completeport; SocketHandle *listenhandle; private: LPFN_ACCEPTEX lpfnacceptex; LPFN_GETACCEPTEXSOCKADDRS lpfngetacceptexsockaddrs; //Initialize functions, check the cpp file //Return value for BOOL function: // true, if succeed; // false, if failed. // private: BOOL InitializeIOCP(void); void DeInitializeIOCP(void); BOOL InitializeSocket(void); void DeInitializeSocket(void); BOOL GetAcceptExFuction(void); private: // CreateThread only can use static function in class // so must transfer the 'this' pointer to lpParam to use non-static function member static DWORD WINAPI WorkerThread(LPVOID lpParam); // the six function member below has same parameter format and return value // //Parameter: // connecthandle - the client socket and addr storage struct for the operation // listeniodata/connectiodata - the io data for the operation // this struct PerIOData MUST begin with WSAOVERLAPPED/OVERLAPPED struct, // To convert the PerIOData pointer to OVERLAPPED pointer. // actually, the first address should be the same, so they are compatible // //Return value: // true, if succeed; // false, if failed. // private: // post function for AcceptEx // no need for do function, ACCEPT_POSTED signal corresponding to listen socket // listeniodata is hold in whole life of master thread // MUST not release in worker thread void PostAcceptEx(PerIOData *listeniodata); BOOL DoAcceptEx(PerIOData *listeniodata); private: // post and do function for recv/send // connectiodata is hold in worker thread void PostRecv(SocketHandle *connecthandle, PerIOData *connectiodata); BOOL DoRecv(SocketHandle *connecthandle, PerIOData *connectiodata); void PostSend(SocketHandle *connecthandle, PerIOData *connectiodata); BOOL DoSend(SocketHandle *connecthandle, PerIOData *connectiodata); };
HttpServer\IOCPServer.cpp:
#include "stdafx.h" #include "IOCPServer.h" // we only post accpetex after do acceptex, if there is no mistake // so the MAX_POST_ACCEPT is the number we post accpetex first // and it is max client number we can accpet in the same time // but we almost can not see difference between 10 and 100 clients, because this program is simple and fast // In test, 100 clients seems to accept immediately in the same time, so this number have no need to be bigger #define MAX_POST_ACCEPT 10 //the port #define SERVERPORT 5863 //backlog, see Stevens' book, the nginx set this to 511 //we have no need to set it to be that big #define BACKLOG 200 //constructor IOCPServer::IOCPServer(void): completeport(NULL), listenhandle(NULL), lpfnacceptex(NULL), lpfngetacceptexsockaddrs(NULL) { IOCP_DBUG("enter IOCPServer\n"); //load the win socket lib WSADATA wsaData; if(NO_ERROR != WSAStartup(MAKEWORD(2,2), &wsaData)) { IOCP_DBUG("WSAStartup WinSock 2.2 failed!\n"); assert(0); } //establish listen socket listenhandle = new SocketHandle(); } // destructor IOCPServer::~IOCPServer(void) { IOCP_DBUG("enter ~IOCPServer\n"); delete listenhandle; } // start the server // we use IOCP instead of select events // of cource, you can register other method, not implement here bool IOCPServer::Start(void) { IOCP_DBUG("enter Start\n"); //Initialize IOCP if(FALSE == InitializeIOCP()) { IOCP_DBUG("InitializeIOCP() failed: %d\n", GetLastError()); DeInitializeIOCP(); return FALSE; } IOCP_DBUG("InitializeIOCP() succeed\n"); //Initialize Socket, associate it with IOCP if(FALSE == InitializeSocket()) { IOCP_DBUG("InitializeSocket() failed: %d\n", GetLastError()); DeInitializeSocket(); return FALSE; } IOCP_DBUG("InitializeSocket() succeed\n"); // get AcceptEx func pointer if(FALSE == GetAcceptExFuction()) { IOCP_DBUG("GetAcceptExFuction() failed: %d\n", GetLastError()); return FALSE; } IOCP_DBUG("GetAcceptExFuction() succeed\n"); // new listeniodata only here // post some ACCEPT_POSTED signal, let the server start for(int i=0; i<MAX_POST_ACCEPT; ++i) { PerIOData *listeniodata = listenhandle->GetNewIOData(); PostAcceptEx(listeniodata); } return TRUE; } //Initialize IOCP BOOL IOCPServer::InitializeIOCP(void) { IOCP_DBUG("enter InitializeIOCP\n"); // establish completeport completeport = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0 ); if ( NULL == completeport) { IOCP_DBUG("CreateIoCompletionPort failed: %d!\n", WSAGetLastError()); return FALSE; } // run worker thread SYSTEM_INFO systeminfo; GetSystemInfo(&systeminfo); for(DWORD i=0; i < systeminfo.dwNumberOfProcessors; ++i) { HANDLE threadhandle; threadhandle = CreateThread(NULL, 0, WorkerThread, (LPVOID)this, 0, NULL); CloseHandle(threadhandle); } return TRUE; } //DeInitialize IOCP void IOCPServer::DeInitializeIOCP(void) { IOCP_DBUG("enter DeInitializeIOCP\n"); CloseHandle(completeport); } //Initialize Socket BOOL IOCPServer::InitializeSocket(void) { IOCP_DBUG("enter InitializeSocket\n"); listenhandle->ssocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); if(INVALID_SOCKET == listenhandle->ssocket) { IOCP_DBUG("WSASocket failed: %d.\n", WSAGetLastError()); return FALSE; } //associate listen socket with IOCP, let IOCP get ACCEPT_POSTED signal if (NULL == CreateIoCompletionPort((HANDLE)listenhandle->ssocket, completeport, (ULONG_PTR)listenhandle, 0)) { IOCP_DBUG("CreateIoCompletionPort() failed: %d.\n", WSAGetLastError()); return FALSE; } // set reuse addr option int reuseaddr = 1; if (SOCKET_ERROR == setsockopt(listenhandle->ssocket, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuseaddr, sizeof(int))) { IOCP_DBUG("listenhandle->ssocket: setsockopt(SO_REUSEADDR) failed %d\n", WSAGetLastError()); closesocket(listenhandle->ssocket); return FALSE; } //bind and listen SOCKADDR_IN ServerAddress; ZeroMemory((char *)&ServerAddress, sizeof(ServerAddress)); ServerAddress.sin_family = AF_INET; ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY); ServerAddress.sin_port = htons(SERVERPORT); if (SOCKET_ERROR == bind(listenhandle->ssocket, (PSOCKADDR) &ServerAddress, sizeof(SOCKADDR_IN))) { IOCP_DBUG("listensocket: bind() failed, %d\n", WSAGetLastError()); closesocket(listenhandle->ssocket); return FALSE; } if (SOCKET_ERROR == listen(listenhandle->ssocket, BACKLOG)) { IOCP_DBUG("listensocket: listen() failed %d\n", WSAGetLastError()); closesocket(listenhandle->ssocket); return FALSE; } return TRUE; } //DeInitialize Socket void IOCPServer::DeInitializeSocket(void) { IOCP_DBUG("enter DeInitializeSocket\n"); closesocket(listenhandle->ssocket); GlobalFree(listenhandle); } //get two function pointer //this has a lower occupancy rate than use win lib directlly BOOL IOCPServer::GetAcceptExFuction(void) { IOCP_DBUG("enter GetAcceptExFuction\n"); SOCKET s = listenhandle->ssocket; if(INVALID_SOCKET == s) { IOCP_DBUG("WSASocket failed: %d.\n", WSAGetLastError()); return FALSE; } // get the fuction pointer for AcceptEx DWORD dwBytes = 0; GUID GuidAcceptEx = WSAID_ACCEPTEX; if (SOCKET_ERROR == WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GUID), &lpfnacceptex, sizeof(LPFN_ACCEPTEX), &dwBytes, NULL, NULL)) { IOCP_DBUG("WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, WSAID_ACCEPTEX) failed" ": %d.\n", WSAGetLastError()); return FALSE; } // get the fuction pointer for GetAcceptExSockAddrs GUID GuidAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS; if (SOCKET_ERROR == WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptExSockAddrs, sizeof(GUID), &lpfngetacceptexsockaddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS), &dwBytes, NULL, NULL)) { IOCP_DBUG("WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, WSAID_ACCEPTEX) failed" ": %d.\n", WSAGetLastError()); return FALSE; } return TRUE; } //worker thread, usually not one, //they are busy until exit. //because these thread is asynchronous, //so one socket can have more than one io. DWORD WINAPI IOCPServer::WorkerThread(LPVOID lpParam) { IOCP_DBUG("enter WorkerThread\n"); IOCPServer* temp = (IOCPServer*)lpParam; LPWSAOVERLAPPED lpoverlapped = NULL; SocketHandle *sockethandle = NULL; PerIOData *periodata = NULL; DWORD bytestransfered = 0; while (TRUE) { // get the status of comleteport BOOL ret = GetQueuedCompletionStatus(temp->completeport, &bytestransfered, (PULONG_PTR)&sockethandle, &lpoverlapped, INFINITE); if(FALSE == ret) { int sockerror = WSAGetLastError(); IOCP_DBUG("GetQueuedCompletionStatus failed: %d.\n", sockerror); if(64 == sockerror) //host is down, client close abnormally { if(temp->listenhandle != sockethandle) { IOCP_DBUG("client %s:%d is DOWN abnormally, we need delete the handle\n", inet_ntoa(sockethandle->ssocketaddr.sin_addr), ntohs(sockethandle->ssocketaddr.sin_port)); // the destructor of sockethandle do recycle delete sockethandle; }else { IOCP_DBUG("something wrong in listenhandle, you need restart the process"); } } continue; } // read the data in completeport periodata = CONTAINING_RECORD(lpoverlapped, PerIOData, overlapped); if(NULL == periodata) { IOCP_DBUG("CONTAINING_RECORD failed: %d.\n", WSAGetLastError()); continue; } // free io and handle, if client close the socket // all normal handle and io free here, if there is no mistake if((0 == bytestransfered) && ( PerIOData::RECV_POSTED == periodata->operationtype || PerIOData::SEND_POSTED == periodata->operationtype)) { IOCP_DBUG("client %s:%d has close the socket, we need close the connection\n", inet_ntoa(sockethandle->ssocketaddr.sin_addr), ntohs(sockethandle->ssocketaddr.sin_port)); // the destructor of sockethandle do recycle delete sockethandle; continue; } switch(periodata->operationtype) { // AcceptEx case PerIOData::ACCEPT_POSTED: { IOCP_DBUG("recv the ACCEPT_POSTED signal\n"); if(FALSE == temp->DoAcceptEx(periodata)) { // here sockethandle is listenhandle // periodata is listeniodata // MUST NOT release them here, let master thread do the bad thing // JUST re post temp->PostAcceptEx(periodata); } } break; // RECV case PerIOData::RECV_POSTED: { IOCP_DBUG("recv the RECV_POSTED signal\n"); // re post, if failed // MUST not close socket here // because one socket may have more io in use if(FALSE == temp->DoRecv(sockethandle, periodata)) { //MUST not force to release the periodata which hold overlapped struct //re post temp->PostRecv(sockethandle, periodata); } } break; // SEND case PerIOData::SEND_POSTED: { IOCP_DBUG("recv the SEND_POSTED signal\n"); // re post, if failed // no need to construct new io, send use the same one with recv if(FALSE == temp->DoSend(sockethandle, periodata)) { // MUST not close socket here // because one socket may have more io in use //MUST not force to release the periodata which hold overlapped struct temp->PostSend(sockethandle, periodata); } } break; case PerIOData::NULL_POSTED: default: IOCP_DBUG("MUST exist a problem, the last error: %d.\n", WSAGetLastError()); break; } //switch }//while return 0; } // post AcceptEx void IOCPServer::PostAcceptEx(PerIOData* listeniodata) { IOCP_DBUG("enter PostAcceptEx\n"); if(NULL == listeniodata) { IOCP_DBUG("this is a fatal mistake, almost no way to reach here\n"); return; } // need new socket before AcceptEx listeniodata->acceptsocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); if(INVALID_SOCKET == listeniodata->acceptsocket) { IOCP_DBUG("WSASocket failed: %d.\n", WSAGetLastError()); return; } // set the connect delay for 3 sec // because AcceptEx will not return, if client just connect but send no bytes // win7 do not support SO_CONNECT_TIME to prevent DDOS // instead, dwReceiveDataLength should be ((sizeof(SOCKADDR_IN)+16)*2) // only get the local and remote addr /* INT timeout = 3; if (SOCKET_ERROR == setsockopt(listeniodata->acceptsocket, SOL_SOCKET, SO_CONNECT_TIME, (const char*)&timeout, sizeof(timeout))) { IOCP_DBUG("setsockopt(SO_CONNECT_TIME) failed: %d.\n", WSAGetLastError()); return; } */ // do some clean // make operationtype signal be ACCEPT_POSTED listeniodata->ResetIO(); listeniodata->operationtype = PerIOData::ACCEPT_POSTED; DWORD dwBytes = 0; if (FALSE == lpfnacceptex(listenhandle->ssocket, listeniodata->acceptsocket, listeniodata->databuf.buf, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, &dwBytes, &listeniodata->overlapped)) { if (WSA_IO_PENDING != WSAGetLastError()) { IOCP_DBUG("AcceptEx() falied: %d.\n", WSAGetLastError()); closesocket(listeniodata->acceptsocket); listeniodata->acceptsocket = -1; return; } } return; } BOOL IOCPServer::DoAcceptEx(PerIOData* listeniodata) { /* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */ // win7 do not support SO_UPDATE_ACCEPT_CONTEXT /* if (SOCKET_ERROR == setsockopt(listeniodata->acceptsocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&listenhandle->ssocket, sizeof(SOCKET))) { IOCP_DBUG("setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed: %d.\n", WSAGetLastError()); return FALSE; } */ //get the addr for client which connect me //for AcceptEx, Should use GetAcceptExSockAddrs SOCKADDR_IN *lplocalsockaddr = NULL; SOCKADDR_IN *lpremotesockaddr = NULL; int localsockaddrlen = sizeof(SOCKADDR_IN); int remotesockaddrlen = sizeof(SOCKADDR_IN); lpfngetacceptexsockaddrs(listeniodata->databuf.buf, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, (LPSOCKADDR*)&lplocalsockaddr, &localsockaddrlen, (LPSOCKADDR*)&lpremotesockaddr, &remotesockaddrlen); SocketHandle *connecthandle = new SocketHandle(); connecthandle->ssocket = listeniodata->acceptsocket; memcpy(&connecthandle->ssocketaddr, lpremotesockaddr, sizeof(SOCKADDR_IN)); if (NULL == CreateIoCompletionPort((HANDLE)connecthandle->ssocket, completeport, (ULONG_PTR)connecthandle, 0)) { IOCP_DBUG("CreateIoCompletionPort() failed: %d.\n", WSAGetLastError()); return FALSE; } // usually we need to recv something, so post recv // we new connecthandle and connectiodata here first PerIOData *connectiodata = connecthandle->GetNewIOData(); PostRecv(connecthandle, connectiodata); //post new one PerIOData *newlisteniodata = listenhandle->GetNewIOData(); PostAcceptEx(newlisteniodata); return TRUE; } // post recv void IOCPServer::PostRecv(SocketHandle* connecthandle, PerIOData* connectiodata) { IOCP_DBUG("enter PostRecv\n"); if(NULL == connecthandle || NULL == connectiodata) { IOCP_DBUG("this is a fatal mistake, almost no way to reach here\n"); return; } // do some clean // make operationtype signal be RECV_POSTED DWORD flags = 0; DWORD recvbytes = 0; connectiodata->ResetIO(); connectiodata->operationtype = PerIOData::RECV_POSTED; //recv the message int nbytes = WSARecv(connecthandle->ssocket, &connectiodata->databuf, 1, &recvbytes, &flags, &connectiodata->overlapped, NULL ); if ((SOCKET_ERROR == nbytes) && (WSA_IO_PENDING != WSAGetLastError())) { IOCP_DBUG("WSARecv() failed: %d.\n", WSAGetLastError()); return; } return; } // do after recv BOOL IOCPServer::DoRecv(SocketHandle* connecthandle, PerIOData* connectiodata) { IOCP_DBUG("enter DoRecv\n"); if(NULL == connecthandle || NULL == connectiodata) { IOCP_DBUG("this is a fatal mistake, almost no way to reach here\n"); return FALSE; } IOCP_DBUG("receive from %s:%d, message: %s.\n", inet_ntoa(connecthandle->ssocketaddr.sin_addr), ntohs(connecthandle->ssocketaddr.sin_port),connectiodata->databuf.buf); //TODO //process the massage // usually we need send after recv PostSend(connecthandle, connectiodata); // handle recv signal complete, post new one //MUST not force to release the periodata which hold overlapped struct //new one periodata PerIOData *newconnectiodata = connecthandle->GetNewIOData(); PostRecv(connecthandle, newconnectiodata); return TRUE; } //post send void IOCPServer::PostSend(SocketHandle* connecthandle, PerIOData* connectiodata) { IOCP_DBUG("enter PostSend\n"); if(NULL == connecthandle || NULL == connectiodata) { IOCP_DBUG("this is a fatal mistake, almost no way to reach here\n"); return; } // do some clean // make operationtype signal be SEND_POSTED DWORD flags = 0; DWORD sendbytes = 0; connectiodata->ResetIO(); connectiodata->operationtype = PerIOData::SEND_POSTED; //TODO //build the message char *temp = "just for test"; strncpy_s(connectiodata->databuf.buf, connectiodata->databuf.len, temp, strlen(temp)); *(connectiodata->databuf.buf + strlen(temp)) = 0; //send the message int nbytes = WSASend(connecthandle->ssocket, &connectiodata->databuf, 1, &sendbytes, flags, &connectiodata->overlapped, NULL ); if ((SOCKET_ERROR == nbytes) && (WSA_IO_PENDING != WSAGetLastError())) { IOCP_DBUG("WSASend() failed: %d.\n", WSAGetLastError()); return; } return; } //DO after send BOOL IOCPServer::DoSend(SocketHandle* connecthandle, PerIOData* connectiodata) { IOCP_DBUG("enter DoSend\n"); if(NULL == connecthandle || NULL == connectiodata) { IOCP_DBUG("this is a fatal mistake, almost no way to reach here\n"); return FALSE; } IOCP_DBUG("send to %s:%d, message: %s.\n", inet_ntoa(connecthandle->ssocketaddr.sin_addr), ntohs(connecthandle->ssocketaddr.sin_port),connectiodata->databuf.buf ); //just do it in the end of one io here //this is dangerous in somewhere else connecthandle->RemoveIOData(connectiodata); return TRUE; }
HttpServer\SocketHandle.h:
#pragma once #include "stdafx.h" #include "PerIOData.h" class SocketHandle { public: SocketHandle(void); virtual ~SocketHandle(void); public: //the socket and its addr the handle hold SOCKET ssocket; SOCKADDR_IN ssocketaddr; //the io list belong to me list<PerIOData*> sockiodata; public: PerIOData* GetNewIOData(void); // check the cpp source file for the reason void RemoveIOData(PerIOData* speriodata); };
HttpServer\SocketHandle.cpp:
#include "stdafx.h" #include "SocketHandle.h" SocketHandle::SocketHandle(void) { ssocket = INVALID_SOCKET; ZeroMemory(&ssocketaddr, sizeof(ssocketaddr)); } SocketHandle::~SocketHandle(void) { //close the socket if( ssocket!=INVALID_SOCKET ) { closesocket(ssocket); ssocket = INVALID_SOCKET; } // release the list list <PerIOData*>::iterator myIterator = sockiodata.begin(); for ( ; myIterator != sockiodata.end(); myIterator++) { delete *myIterator; *myIterator = NULL; } sockiodata.clear(); } // new iodata and add it in list //return new io which will be used PerIOData* SocketHandle::GetNewIOData(void) { PerIOData* speriodata = new PerIOData(); sockiodata.push_back(speriodata); return speriodata; } //delete the io transfered and erase it form list //MUST not force to release the periodata which hold overlapped struct //let the deconstruct func do the recycle //we need it just in the end of one io's life. //just for case, some ugly client keep sending message to me with no interval void SocketHandle::RemoveIOData(PerIOData* speriodata) { if(NULL == speriodata) { IOCP_DBUG("you just transfer a NULL pointer\n"); return; } list <PerIOData*>::iterator myIterator = sockiodata.begin(); for ( ; myIterator != sockiodata.end(); myIterator++) { if(*myIterator == speriodata) { delete *myIterator; *myIterator = NULL; sockiodata.erase(myIterator); break; } } }
HttpServer\PerIOData.h:
#pragma once #include "stdafx.h" // per io data for socket handle // one socket can has more than one io //WSAOVERLAPPED struct must be the first in memory of this class // so this class and its base class MUST not have virtual func class PerIOData { public: PerIOData(void); ~PerIOData(void); public: // overlapped struct, must be in the first place of class memory WSAOVERLAPPED overlapped; //just for ACCEPT_POSTED signal SOCKET acceptsocket; //the buffer of me WSABUF databuf; //the signal belong to me DWORD operationtype; public: void ResetIO(void); // this four signal is the public signal for other class, IOCPServer etc.. // ACCEPT_POSTED - signal for accept // RECV_POSTED - signal for recv // SEND_POSTED - signal for send // NULL_POSTED - terminal signal, no meaning // public: typedef enum { ACCEPT_POSTED, RECV_POSTED, SEND_POSTED, NULL_POSTED }OPERATION_TYPE; };
HttpServer\PerIOData.cpp:
#include "stdafx.h" #include "PerIOData.h" // default buffer size #define BUFFERSIZE 1024 //new buffer and Initialize PerIOData::PerIOData(void): operationtype(NULL_POSTED), acceptsocket(INVALID_SOCKET) { ZeroMemory(&overlapped, sizeof(overlapped)); databuf.buf = new char[BUFFERSIZE]; databuf.len = BUFFERSIZE; ZeroMemory(databuf.buf, databuf.len); } //delete the buffer PerIOData::~PerIOData(void) { if(NULL != databuf.buf) { delete [] databuf.buf; databuf.buf = NULL; } } //reset buffer and overlapped of io void PerIOData::ResetIO(void) { databuf.len = BUFFERSIZE; ZeroMemory(databuf.buf, databuf.len); ZeroMemory(&overlapped, sizeof(WSAOVERLAPPED)); }
相关文章推荐
- 统一完成端口Iocp和Epoll
- IOCP完成端口介绍及完成端口内部实现
- 可伸缩的IO完成端口服务器模型(IOCP)(中文版)
- DELPHI中完成端口(IOCP)的简单分析(3)
- DELPHI高性能大容量SOCKET并发:IOCP完成端口例子介绍
- 【windows核心编程】IO完成端口(IOCP)复制文件小例
- 使用AcceptEx方法的完成端口
- 可伸缩的IO完成端口服务器模型(IOCP)(英文版)
- DELPHI中完成端口(IOCP)的简单分析(4)
- DELPHI中完成端口(IOCP)的简单分析(1) 推荐
- Windows下使用winsock2与完成端口(IOCP)编写高伸缩性的网络服务器
- 完成端口(IOCP)--实例
- 完成端口(IOCP)怎么判断某个连接是否断开
- Delphi中完成端口(IOCP)的简单分析
- DELPHI中完成端口(IOCP)的简单分析
- IOCP完成端口与长连接通讯
- DELPHI中完成端口(IOCP)的简单分析(2)
- 【windows核心编程】IO完成端口(IOCP)复制文件小例前简单说明
- 完成端口(IOCP)编程探讨
- 完成端口重叠I/O模型的服务器中,如何存储和管理数万个socket句柄—IOCP代码