#include <WinSock2.h> #include <MSTcpIP.h> #include <Windows.h> #include <process.h> #include <set> using namespace std; #define I_PORT 1666 #define I_ADDR "0.0.0.0" #define DFT_BUFFER_SIZE 4096 #define OPT_READ 0 #define OPT_WRITE 1 class CClient { public: CClient() { } ~CClient() { } SOCKET m_client; DWORD m_tranSize; char* m_buffer; string m_ip; }; class CPerData { public: CPerData() { memset(&m_overlp,0,sizeof(WSAOVERLAPPED)); m_Buffer.buf = m_Buf; m_Buffer.len = DFT_BUFFER_SIZE; m_opt = -1; } ~CPerData() { } WSAOVERLAPPED m_overlp; WSABUF m_Buffer; int m_opt; char m_Buf[DFT_BUFFER_SIZE]; }; class CIocp { public: CIocp() { m_hIocp = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,0); m_sListen = WSASocket(AF_INET,SOCK_STREAM,0,0,0,WSA_FLAG_OVERLAPPED); m_addr.sin_family = AF_INET; m_addr.sin_port=htons(I_PORT); m_addr.sin_addr.S_un.S_addr = inet_addr(I_ADDR); int iret = bind(m_sListen,(sockaddr*)&m_addr, sizeof(sockaddr)); unsigned int tid; m_hListen = (HANDLE)::_beginthreadex(0,0, CIocp::ListenProc,this, 0, &tid); m_wsaEvent = ::WSACreateEvent(); ::WSAEventSelect(m_sListen, m_wsaEvent, FD_ACCEPT|FD_CLOSE); iret = ::listen(m_sListen,5); SYSTEM_INFO sys; ::GetSystemInfo(&sys); for (int i=0;i<sys.dwNumberOfProcessors;i++) //In fact, you should be create 2*number of cup +2 threads,here just test { m_hWork[i] = (HANDLE)::_beginthreadex(0,0, CIocp::ConProc,this, 0, &tid); } } ~CIocp() { } private: int InitListen() { int error = 0; char _Name[100]; hostent * pHostEntry; in_addr rAddr; /* error = gethostname ( _Name, sizeof(_Name) ); if( 0 == error ) { pHostEntry = gethostbyname( _Name ); if( pHostEntry != NULL ) { memcpy( &rAddr, pHostEntry->h_addr_list[0], sizeof(struct in_addr) ); pm_HostIpAddress->assign( inet_ntoa( rAddr ) ); } else { error = WSAGetLastError(); return error; } } else { error = WSAGetLastError(); return error; } if(0 == error) { m_sListen=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); if(m_sListen==INVALID_SOCKET) { error = WSAGetLastError(); return error; } } */ if(0 == error) { int r = 0; int TimeOut=6000; r = setsockopt(m_sListen,SOL_SOCKET,SO_SNDTIMEO,(char *)&TimeOut,sizeof(TimeOut)); int size; size = 32768; r = setsockopt(m_sListen,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)); size = 32768; r = setsockopt(m_sListen,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)); int on = 1; r = setsockopt(m_sListen, SOL_SOCKET, SO_KEEPALIVE,(const char *) &on, sizeof( int ) ); { int iKeepAlive = -1; int nOutSize = sizeof(int); if (getsockopt(m_sListen, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &nOutSize) == SOCKET_ERROR) { } else if (iKeepAlive == 1) { tcp_keepalive inKeepAlive; memset(&inKeepAlive, 0, sizeof(tcp_keepalive)); unsigned long ulInLen = sizeof(tcp_keepalive); tcp_keepalive outKeepAlive; unsigned long ulOutLen = sizeof(tcp_keepalive); unsigned long ulBytesReturn = 0; inKeepAlive.onoff = 1; inKeepAlive.keepaliveinterval = 60000; inKeepAlive.keepalivetime = 3; if (WSAIoctl(m_sListen, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen, (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL) == SOCKET_ERROR) { r = -1; } } } } /* if(0==error) { sockaddr_in InternetAddr; InternetAddr.sin_family=AF_INET; InternetAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY); InternetAddr.sin_port=htons(SvrPort); if(bind(m_sListen, (PSOCKADDR )&InternetAddr, sizeof(InternetAddr))==SOCKET_ERROR) { error=GetLastError(); return error; } } */ } void LisenWork() { while(::WSAWaitForMultipleEvents(1,&m_wsaEvent,TRUE,INFINITE,FALSE) != WAIT_FAILED) { ::WSAResetEvent(m_wsaEvent); WSANETWORKEVENTS nwEvnts ; ::WSAEnumNetworkEvents(m_sListen, m_wsaEvent, &nwEvnts); if ((nwEvnts.lNetworkEvents & FD_ACCEPT) && (nwEvnts.iErrorCode[FD_ACCEPT_BIT] == 0)) { int err = 0; SOCKET s = ::WSAAccept(m_sListen,0,0,0,0); CClient* client = new CClient; client->m_client = s; CPerData* pdata = new CPerData(); pdata->m_opt = 0; m_client.insert(client); SOCKADDR_IN addr = {0}; int asize = 0; ::getpeername(s, (SOCKADDR*)&addr,&asize); client->m_ip = inet_ntoa(addr.sin_addr); err = (int)::CreateIoCompletionPort((HANDLE)client->m_client, m_hIocp,(ULONG_PTR)client,0 ); DWORD flag=0; //must be set 0,or wsarecv return -1 and getlasterror is 10045 DWORD rsize = 0; err = ::WSARecv(client->m_client,&pdata->m_Buffer,1,&rsize,&flag,&pdata->m_overlp,NULL); err =::GetLastError(); int i = 0; } else if ((nwEvnts.lNetworkEvents & FD_CLOSE)&&(nwEvnts.iErrorCode[FD_CLOSE_BIT] == 0)) { ::closesocket(m_sListen); return; } } } static unsigned int WINAPI ListenProc(void* proc) { CIocp* pThis = reinterpret_cast<CIocp*>(proc); pThis->LisenWork(); return 0; } void RemoveClient(CClient* client) { ::closesocket(client->m_client); m_client.erase(m_client.find(client)); } void ConWork() { while(true) { DWORD nSize = 0; CClient* client = NULL; CPerData* pdata=NULL; int ret = ::GetQueuedCompletionStatus(m_hIocp, &nSize,(PULONG_PTR)&client, (LPOVERLAPPED*)&pdata, INFINITE); if (ret != 0 ) { if (nSize==0) //client closed { RemoveClient(client); continue; } if (pdata->m_opt==OPT_READ) { //do something.... CPerData* psdata = pdata; pdata->m_Buffer.len = nSize; psdata->m_opt = OPT_WRITE; DWORD tsize=0; DWORD iflag=0; memset(&psdata->m_overlp,0,sizeof(psdata->m_overlp)); int err = ::WSASend(client->m_client,&psdata->m_Buffer, 1, &tsize,iflag, (WSAOVERLAPPED*)psdata,0 ); err = ::GetLastError(); } else if (pdata->m_opt==OPT_WRITE) { DWORD tsize=0; DWORD iflag=0; pdata->m_Buffer.len = DFT_BUFFER_SIZE; memset(&pdata->m_overlp,0,sizeof(pdata->m_overlp)); pdata->m_opt = OPT_READ; int err = ::WSARecv(client->m_client, &pdata->m_Buffer, 1, &tsize, &iflag, (WSAOVERLAPPED*)pdata,0); err = ::GetLastError(); int i = 0; } } else { RemoveClient(client); continue; } } } static unsigned int WINAPI ConProc(void* proc) { CIocp* pThis = reinterpret_cast<CIocp*>(proc); pThis->ConWork(); return 0; } private: SOCKET m_sListen; HANDLE m_hIocp; SOCKADDR_IN m_addr; HANDLE m_hListen; HANDLE m_hWork[2]; WSAEVENT m_wsaEvent; set<CClient*> m_client; };