简单的iocp例子

28 篇文章 0 订阅
23 篇文章 0 订阅
#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;

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值