www.pudn.com > mischat.rar > IocpModeSvr.cpp


// IocpModeSvr.cpp: implementation of the CIocpModeSvr class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "IocpModeSvr.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#pragma  warning(disable:4800) 
 
DWORD WINAPI ServerWorkerProc(LPVOID lParam) 
{ 
	CIocpModeSvr* pSvr=(CIocpModeSvr*)lParam; 
	HANDLE CompletionPort=pSvr->CompletionPort; 
	DWORD ByteTransferred; 
	LPPER_HANDLE_DATA PerHandleData; 
	PPER_IO_OPERATION_DATA PerIoData; 
	DWORD RecvByte; 
	while(true) 
	{ 
		bool bSuccess=GetQueuedCompletionStatus(CompletionPort, 
												&ByteTransferred, 
												(LPDWORD)&PerHandleData, 
												(LPOVERLAPPED* )&PerIoData, 
												INFINITE); 
		//退出信号到达,退出线程 
		if(ByteTransferred==-1 && PerIoData==NULL) 
		{ 
			return 1L; 
		} 
		//客户机已经断开连接或者连接出现错误 
		if(ByteTransferred==0 &&  
		   (PerIoData->OperType==RECV_POSTED || PerIoData->OperType==SEND_POSTED)) 
		{ 
			//将该客户端数据删除 
			int arrSize=0; 
			bool bFind=false; 
			::EnterCriticalSection(&pSvr->cInfoSection); 
			while(arrSizeClientInfo.GetSize()) 
			{ 
				PER_HANDLE_DATA pPerHandleData=pSvr->ClientInfo.GetAt(arrSize); 
				if((pPerHandleData.IpAddr==PerHandleData->IpAddr) && 
				   (pPerHandleData.sClient==PerHandleData->sClient)) 
				{ 
					bFind=true; 
					pSvr->ClientInfo.RemoveAt(arrSize); 
					break; 
				} 
				arrSize++; 
			} 
			::LeaveCriticalSection(&pSvr->cInfoSection); 
			if(bFind) 
			{ 
				//记录退出日志 
				CString LogStr; 
				in_addr in_A; 
				in_A.S_un.S_addr=PerHandleData->IpAddr; 
				LogStr.Format("IP:%s 已断开连接",inet_ntoa(in_A)); 
				pSvr->WriteLogString(LogStr,PerHandleData->IpAddr); 
				TRACE("\nSocket : %d Disconneted",PerHandleData->sClient); 
				//调用回调函数,通知上层该客户端已经断开 
				//pSvr->m_pProcessRecvData(PerHandleData->IpAddr, 
				//	PerHandleData->sClient, 
				//	NULL, 
				//	0,FALSE); 
				//关闭套接口 
				closesocket(PerHandleData->sClient); 
				GlobalFree(PerHandleData); 
				GlobalFree(PerIoData); 
			} 
			continue; 
		} 
		//为读操作完成,处理数据 
		if(PerIoData->OperType==RECV_POSTED) 
		{ 
			//调用回调函数,处理数据 
			pSvr->m_pProcessRecvData(PerHandleData->IpAddr, 
				                     PerHandleData->sClient, 
									 PerIoData->RecvBuf, 
									 ByteTransferred,FALSE); 
			//将源数据置空 
			memset(PerIoData->RecvBuf,0,BUFFER_SIZE); 
			ByteTransferred=0; 
			//重置IO操作数据 
			unsigned long Flag=0; 
			ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED)); 
			 
			PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf; 
			PerIoData->RecvDataBuf.len=BUFFER_SIZE; 
			PerIoData->OperType=RECV_POSTED; 
			//提交另一个Recv请求 
			WSARecv(PerHandleData->sClient, 
				&(PerIoData->RecvDataBuf), 
				1, 
				&RecvByte, 
				&Flag, 
				&(PerIoData->OverLapped), 
				NULL); 
		} 
		//发送完成,置空缓冲区,释放缓冲区 
		if(PerIoData->OperType==SEND_POSTED) 
		{ 
			memset(PerIoData,0,sizeof(PER_IO_OPERATION_DATA)); 
			GlobalFree(PerIoData); 
			ByteTransferred=0; 
		} 
	} 
	return 0L; 
} 
DWORD WINAPI ListenProc(LPVOID lParam) 
{ 
	CIocpModeSvr* pSvr=(CIocpModeSvr*)lParam; 
	SOCKET Accept; 
	while(true) 
	{ 
		//接收客户的请求 
		Accept=WSAAccept(pSvr->ListenSocket,NULL,NULL,pSvr->m_pConditionFunc,0); 
		if(WSAGetLastError()==WSAECONNREFUSED) continue; 
		//申请新的句柄操作数据 
 
		LPPER_HANDLE_DATA PerHandleData=(LPPER_HANDLE_DATA) \ 
			                            GlobalAlloc(GPTR, 
										sizeof(PER_HANDLE_DATA) 
										); 
		//取得客户端信息 
		sockaddr soad; 
		sockaddr_in in; 
		int len=sizeof(soad); 
		if(getpeername(Accept,&soad,&len)==SOCKET_ERROR) 
		{ 
			CString LogStr; 
			LogStr.Format("getpeername() faild : %d",GetLastError()); 
			pSvr->WriteLogString(LogStr); 
		} 
		else{ 
			memcpy(&in,&soad,sizeof(sockaddr)); 
		} 
		//句柄数据 
		PerHandleData->sClient=Accept; 
		PerHandleData->IpAddr=in.sin_addr.S_un.S_addr; 
		//存储客户信息 
		::EnterCriticalSection(&pSvr->cInfoSection); 
		pSvr->ClientInfo.Add(*PerHandleData); 
		::LeaveCriticalSection(&pSvr->cInfoSection); 
		//转储信息 
		CString LogStr; 
		LogStr.Format("IP:%s 已连接!",inet_ntoa(in.sin_addr)); 
		pSvr->WriteLogString(LogStr,PerHandleData->IpAddr); 
 
		TRACE("\nUserIP: %s ,Socket : %d Connected!",inet_ntoa(in.sin_addr),Accept); 
		//关联客户端口到完成端口,句柄数据在此时被绑定到完成端口 
		CreateIoCompletionPort((HANDLE)Accept, 
			                   pSvr->CompletionPort, 
							   (DWORD)PerHandleData, 
							   0); 
		//Io操作数据标志 
 
		PPER_IO_OPERATION_DATA PerIoData=(PPER_IO_OPERATION_DATA) \ 
			                              GlobalAlloc(GPTR, 
										  sizeof(PER_IO_OPERATION_DATA)); 
		unsigned long  Flag=0; 
		DWORD RecvByte; 
		ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED)); 
 
		PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf; 
		PerIoData->RecvDataBuf.len=BUFFER_SIZE; 
		PerIoData->OperType=RECV_POSTED; 
		//提交首个接收数据请求 
		//这时 
		//如果客户端断开连接 
		//则也可以以接收数据时得到通知	 
		WSARecv(PerHandleData->sClient, 
			&(PerIoData->RecvDataBuf), 
			1, 
			&RecvByte, 
			&Flag, 
			&(PerIoData->OverLapped), 
			NULL); 
	} 
} 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
CIocpModeSvr::CIocpModeSvr() 
{ 
	IsStart=false; 
} 
CIocpModeSvr::~CIocpModeSvr() 
{ 
} 
bool CIocpModeSvr::SendMsg(LPCTSTR TargetIp,char * pData,unsigned long Length) 
{ 
	if(TargetIp=="" || pData==NULL || Length==0 || !IsStart) 
		return false; 
 
	bool bFind=false; 
	PER_HANDLE_DATA pPerHandleData; 
	memset(&pPerHandleData,0,sizeof(PER_HANDLE_DATA)); 
 
	unsigned long tIp=inet_addr(TargetIp); 
	//在表中查找该客户端数据并发送数据 
	 
	::EnterCriticalSection(&cInfoSection); 
	int arrSize=0; 
	while(arrSize4096)return false; 
 
	//申请操作键 
	PPER_IO_OPERATION_DATA PerIoData=(PPER_IO_OPERATION_DATA) \ 
									  GlobalAlloc(GPTR, 
		                              sizeof(PER_IO_OPERATION_DATA)); 
 
	//准备缓冲 
	unsigned long  Flag=0; 
	DWORD SendByte; 
	ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED)); 
	memcpy(PerIoData->SendBuf,pData,Length); 
	PerIoData->SendDataBuf.buf=PerIoData->SendBuf; 
	PerIoData->SendDataBuf.len=Length; 
	PerIoData->OperType=SEND_POSTED; 
	int bRet=WSASend(sClient, 
		             &(PerIoData->SendDataBuf), 
		             1, 
		             &SendByte, 
		             Flag, 
		             &(PerIoData->OverLapped), 
		             NULL); 
	if(bRet==SOCKET_ERROR && GetLastError()!=WSA_IO_PENDING) 
	{ 
		CString LogStr; 
		LogStr.Format("WSASend With Error : %d",GetLastError()); 
		WriteLogString(LogStr); 
		return false; 
	} 
	else return true; 
	 
	return false; 
} 
bool CIocpModeSvr::SendMsgToAll(char * pData,unsigned long Length) 
{ 
	if(pData==NULL || Length==0 || !IsStart)return false; 
 
	::EnterCriticalSection(&cInfoSection); 
	int arrSize=0; 
	PER_HANDLE_DATA pPerHandleData; 
	while(arrSizeassign( "" ); 
		 
		LogStr.Format("WSAStartUp Faild With Error: %d",Error); 
		WriteLogString(LogStr); 
		 
		return Error; 
	} 
	//Make Version 
	if ( LOBYTE( wsaData.wVersion ) != 2 || 
		HIBYTE( wsaData.wVersion ) != 2 ) 
	{ 
		WSACleanup( ); 
		 
		WriteLogString("The Local Net Version Is not 2"); 
		 
		return -1; 
	} 
	//Get Host Ip 
	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) ); 
			pHostIpAddress->assign( inet_ntoa( rAddr ) ); 
		} 
		else 
		{ 
			Error = WSAGetLastError(); 
			LogStr.Format("GetHostIp faild with Error: %d",Error); 
			WriteLogString(LogStr); 
			return Error; 
			 
		} 
	} 
	else 
	{ 
		Error = WSAGetLastError(); 
		LogStr.Format("gethostname faild with Error: %d",Error); 
		WriteLogString(LogStr); 
		return Error; 
	} 
	if(0==Error) 
	{ 
		//创建侦听端口 
		ListenSocket=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); 
		if(ListenSocket==INVALID_SOCKET) 
		{ 
			Error = WSAGetLastError(); 
			LogStr.Format("CreateSocket faild with Error: %d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
	} 
	//绑定到目标地址 
	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(ListenSocket, 
			    (PSOCKADDR )&InternetAddr, 
				sizeof(InternetAddr))==SOCKET_ERROR) 
		{ 
			Error=GetLastError(); 
			LogStr.Format("bind Socket faild with Error: %d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
	} 
	//侦听端口上的连接请求 
	if(0==Error) 
	{ 
		if(	listen(ListenSocket,5)==SOCKET_ERROR) 
		{ 
			Error=GetLastError(); 
			LogStr.Format("listen Socket faild with Error: %d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
	} 
	//创建完成端口句柄 
	if(0==Error) 
	{ 
		CompletionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); 
		if(CompletionPort==INVALID_HANDLE_VALUE) 
		{ 
			Error=GetLastError(); 
			LogStr.Format("CreateIoCompletionPort faild with Error: %d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
	} 
	//启动工作线程,线程数为CPU处理器数量*2+2 
	if(0==Error) 
	{	 
		SYSTEM_INFO sys_Info; 
		GetSystemInfo(&sys_Info); 
		for(int i=0;i