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


// NetClient.cpp: implementation of the CNetClient class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "NetClient.h" 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
CNetClient::CNetClient() 
{ 
	IsStart=false; 
	bOprUnInit=false; 
	m_pProcessRecvData=NULL; 
	hSendEvent=CreateEvent(NULL,false,false,NULL); 
	hWorkEvent=CreateEvent(NULL,false,false,NULL); 
	hExitEvent=CreateEvent(NULL,false,false,NULL); 
} 
CNetClient::~CNetClient() 
{ 
	CloseHandle(hSendEvent); 
	CloseHandle(hWorkEvent); 
	CloseHandle(hExitEvent); 
} 
DWORD _stdcall SendProc(LPVOID pParam) 
{ 
	CNetClient * pNetClient=(CNetClient*) pParam; 
	HANDLE event[2]; 
	event[0]=pNetClient->hSendEvent; 
	event[1]=pNetClient->hExitEvent; 
 
	while(true) 
	{ 
		//Sleep(1); 
		::EnterCriticalSection(&pNetClient->SendMsgQueSection); 
		//队列为空,等待发送事件触发 
		if(pNetClient->SendMsgQueue.IsEmpty()) 
		{ 
			::LeaveCriticalSection(&pNetClient->SendMsgQueSection); 
			//为空,或者发送完毕 
			ResetEvent(pNetClient->hSendEvent); 
			TRACE("\nTheSendProc Is Waiting....");	 
			DWORD Index=::WaitForMultipleObjects(2,event,false,INFINITE); 
			if((Index-WAIT_OBJECT_0)==1)return 0L; 
		} 
		else 
		{ 
			//取下一个结点,并发送 
			MSG_NODE p=pNetClient->SendMsgQueue.DeQueue(); 
			//释放队列 
			::LeaveCriticalSection(&pNetClient->SendMsgQueSection); 
			DWORD retlen; 
			bool bRet=pNetClient->m_sClient.SendMsg(p.pData,p.DataLength,&retlen,WSA_INFINITE); 
			if(bRet==false || retlen!=p.DataLength) 
			{ 
				if(GetLastError()!=CLIENT_FUNERROR) 
				pNetClient->m_pProcessRecvData(NULL,0,FALSE); 
				pNetClient->UnInit(); 
			}	 
		} 
	} 
	return 0L; 
} 
DWORD _stdcall WorkProc(LPVOID pParam) 
{ 
	CNetClient* pNetClient=(CNetClient*)pParam; 
	HANDLE event[2]; 
	event[0]=pNetClient->hWorkEvent; 
	event[1]=pNetClient->hExitEvent; 
	 
	while(true) 
	{ 
		Sleep(1); 
		::EnterCriticalSection(&pNetClient->RecvMsgQueSection); 
		//队列为空,等待发送事件触发 
		if(pNetClient->RecvMsgQueue.IsEmpty()) 
		{ 
			::LeaveCriticalSection(&pNetClient->RecvMsgQueSection); 
			//为空,或者发送完毕 
			ResetEvent(pNetClient->hWorkEvent); 
			TRACE("\nTheWorkProc Is Waiting....");			 
			DWORD Index=::WaitForMultipleObjects(2,event,false,INFINITE); 
			if((Index-WAIT_OBJECT_0)==1)return 0L; 
		} 
		else 
		{ 
			//取下一个结点,并发送 
			MSG_NODE p=pNetClient->RecvMsgQueue.DeQueue(); 
			//释放队列 
			::LeaveCriticalSection(&pNetClient->RecvMsgQueSection); 
			//调用回调函数,处理数据 
			pNetClient->m_pProcessRecvData(p.pData,p.DataLength,FALSE); 
		} 
	} 
	return 0L; 
} 
DWORD _stdcall RecvProc(LPVOID pParam) 
{ 
	CNetClient * pNetClient=(CNetClient*)pParam; 
	char RecvBuf[BUFFER_SIZE]; 
	DWORD retlen; 
	while (true) 
	{ 
		Sleep(1); 
		TRACE("\nTheRecvThread Is Waiting..."); 
		if(!pNetClient->m_sClient.RecvMsg(RecvBuf,BUFFER_SIZE,&retlen,WSA_INFINITE) &&  GetLastError()!=CLIENT_FUNERROR) 
		{ 
			if(pNetClient->bOprUnInit)return 0L;//应用程序请求退出	 
			//连接已经被断开,通知上层(通过调用回调函数) 
			pNetClient->m_pProcessRecvData(NULL,0,FALSE); 
			pNetClient->UnInit(); 
			return 0L; 
		} 
		else 
		{ 
			//没收到字节?还是出错 
			if(retlen==0) 
			{ 
				pNetClient->m_pProcessRecvData(NULL,0,FALSE); 
				pNetClient->UnInit(); 
				return 0L; 
			} 
			//将接收到的数据放到接收队列里 
			MSG_NODE Msg; 
			Msg.DataLength=retlen; 
			memcpy(Msg.pData,RecvBuf,retlen); 
			//插入消息队列 
			::EnterCriticalSection(&pNetClient->RecvMsgQueSection); 
			if(pNetClient->SendMsgQueue.IsEmpty()) 
			{ 
				pNetClient->RecvMsgQueue.EnQueue(Msg); 
				::LeaveCriticalSection(&pNetClient->RecvMsgQueSection); 
				//如果消息队列为空,告诉工作线程可以进行工作了 
				SetEvent(pNetClient->hWorkEvent); 
			} 
			else 
			{ 
				pNetClient->RecvMsgQueue.EnQueue(Msg); 
				::LeaveCriticalSection(&pNetClient->RecvMsgQueSection); 
			} 
		} 
	} 
	return 0L; 
} 
bool CNetClient::Init(CProcessRecvData* pProcessRecvData,LPCTSTR szSvrAddr, unsigned long iSvrPort) 
{ 
	if(pProcessRecvData==NULL //回调函数空 
		|| szSvrAddr==NULL //地址空 
		|| IsStart)//已经启动过了 
		return false;	 
	::InitializeCriticalSection(&SendMsgQueSection); 
	::InitializeCriticalSection(&RecvMsgQueSection);	 
	IsStart=false; 
	bOprUnInit=false; 
	m_pProcessRecvData=pProcessRecvData; 
	int  bRet=InitNetWork(szSvrAddr,iSvrPort,HostIpAddr); 
	if(0==bRet) 
	{ 
		IsStart=true; 
		return true; 
	} 
	else 
		return false; 
} 
void CNetClient::UnInit() 
{ 
	if(!IsStart)return; 
	bOprUnInit=true; 
	SetEvent(hExitEvent);	 
	SetEvent(hExitEvent); 
	m_sClient.UnInit();	 
	::DeleteCriticalSection(&SendMsgQueSection); 
	::DeleteCriticalSection(&RecvMsgQueSection); 
	SendMsgQueue.MakeEmpty(); 
	RecvMsgQueue.MakeEmpty();	 
	m_pProcessRecvData=NULL; 
	IsStart=false; 
} 
int CNetClient::InitNetWork(LPCTSTR szSvrAddr,unsigned int SvrPort,LPCTSTR pHostIpAddress) 
{ 
	CString LogStr; 
	int Error=0; 
	WSADATA wsaData; 
	char Name[100]; 
	hostent *pHostEntry; 
	in_addr rAddr; 
	memset((void *)pHostIpAddress,0,sizeof(pHostIpAddress)); 
	//Net Start Up 
	Error=WSAStartup(MAKEWORD(0x02,0x02),&wsaData); 
	if(Error!=0) 
	{ 
		Error = WSAGetLastError(); 
		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) ); 
			sprintf((char * )pHostIpAddress,"%s",inet_ntoa( rAddr )); 
		} 
		else 
		{ 
			Error = WSAGetLastError(); 
			LogStr.Format("GetHostIp faild with Error: %d",Error); 
			WriteLogString(LogStr); 
 
		} 
	} 
	else 
	{ 
		Error = WSAGetLastError(); 
		LogStr.Format("gethostname faild with Error: %d",Error); 
		WriteLogString(LogStr); 
	} 
	//Socket Create 
	if(0==Error) 
	{ 
		if(!m_sClient.CreateSocket(SOCK_STREAM)) 
		{ 
			Error=WSAGetLastError(); 
			LogStr.Format("Create Client Socket Faild :%d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
	} 
	if(0==Error) 
	{ 
		if(!m_sClient.ConnectSocket((char *)szSvrAddr,SvrPort)) 
		{ 
			Error=WSAGetLastError(); 
			LogStr.Format("Create Client Socket Faild :%d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
	} 
	//启动工作线程,并升高工作线程的等级至最高 
	if(0==Error) 
	{ 
		HANDLE WorkHan=0; 
		unsigned long WorkID; 
		if((WorkHan=CreateThread(NULL,0,WorkProc,this,0,&WorkID))==NULL) 
		{ 
			Error=GetLastError(); 
			LogStr.Format("Create WorkThread Faild With Error %d",Error); 
			WriteLogString(LogStr); 
			return Error; 
		} 
		//SetThreadPriority(WorkHan,THREAD_PRIORITY_HIGHEST); 
		CloseHandle(WorkHan); 
	} 
	//启动接收线程 
	if(0==Error) 
	{ 
		HANDLE RecvHan=0; 
		unsigned long RecvID; 
		if((RecvHan=CreateThread(NULL,0,RecvProc,this,0,&RecvID))==NULL) 
		{ 
			Error=GetLastError(); 
			LogStr.Format("Create RecvThread Faild With Error %d",Error); 
			WriteLogString(LogStr); 
			SetEvent(hExitEvent);//退出先前创建的线程 
			return Error; 
		} 
		CloseHandle(RecvHan); 
	} 
	//启动发送线程 
	if(0==Error) 
	{ 
		HANDLE ThreHan; 
		unsigned long ThrID; 
		if((ThreHan=CreateThread(NULL,0,SendProc,this,0,&ThrID))==NULL) 
		{ 
			Error=GetLastError(); 
			LogStr.Format("Create SEND Thred Faild With Error %d",Error); 
			WriteLogString(LogStr); 
			SetEvent(hExitEvent);//退出先前创建的线程 
			return Error; 
		} 
		CloseHandle(ThreHan); 
	} 
	return Error; 
} 
bool CNetClient::SendMsg(char * pData,unsigned long DataLength) 
{		 
		//未调用初始化函数 
		if(!IsStart || pData==NULL || DataLength==0 || DataLength>4096)return false; 
		//构造消息 
		MSG_NODE Msg; 
		Msg.DataLength=DataLength; 
		memcpy(Msg.pData,pData,DataLength); 
		//插入消息队列 
		::EnterCriticalSection(&SendMsgQueSection); 
		if(SendMsgQueue.IsEmpty()) 
		{ 
			SendMsgQueue.EnQueue(Msg); 
			::LeaveCriticalSection(&SendMsgQueSection); 
			//如果消息队列为空,告诉等待的发送线程可以发送了 
			SetEvent(hSendEvent); 
		} 
		else 
		{ 
			SendMsgQueue.EnQueue(Msg); 
			::LeaveCriticalSection(&SendMsgQueSection); 
		} 
		return true; 
} 
void CNetClient::WriteLogString(CString strLog) 
{ 
	//SYSTEMTIME sysTm; 
	//::GetLocalTime(&sysTm); 
	char* p=strLog.GetBuffer (); 
	m_pProcessRecvData(p,strLog.GetLength (),TRUE); 
	strLog.ReleaseBuffer (); 
} 
/******************************************************************** 
函数名  : Queue::~Queue()  
输入参数: 
输出参数: 
功能描述: 队列析构函灵敏,清空所有队列元素 
全局变量: 无 
调用模块:  
附加说明:  
********************************************************************/ 
template   Queue::~Queue() 
{ 
	QueueNode *p=front; 
	while(front!=NULL) 
	{ 
		p=front; 
		front=front->link; 
		delete p; 
	} 
} 
/******************************************************************** 
函数名  : Queue::EnQueue 
输入参数: 
const T & item :要插入的结点的引用 
输出参数: 
功能描述: 在队列中插入一个结点 
全局变量: 无 
调用模块:  
附加说明:  
********************************************************************/ 
template  void Queue::EnQueue(const T & item) 
{ 
	if(front==NULL)front=rear=new QueueNode(item,NULL); 
	else rear=rear->link=new QueueNode(item,NULL); 
} 
/******************************************************************** 
函数名  : Queue::DeQueue()  
输入参数: 
T  :返回被删除结点的值 
输出参数: 
功能描述: 从队列中取出一个结点,并返回该结点的值 
全局变量: 无 
调用模块:  
附加说明:  
********************************************************************/ 
template  T Queue::DeQueue() 
{ 
	T  retvalue; 
	memset(&retvalue,0,sizeof(T)); 
	if(IsEmpty()) 
		return retvalue; 
	QueueNode * p=front; 
	retvalue=p->data; 
	front=front->link; 
	delete p; 
	return retvalue; 
} 
/******************************************************************** 
函数名  : Queue::MakeEmpty()  
输入参数: 
输出参数: 
功能描述: 将队列元素清空 
全局变量: 无 
调用模块:  
附加说明:  
********************************************************************/ 
template  void Queue::MakeEmpty() 
{ 
	if(front==NULL)return ; 
	QueueNode * p=front; 
	while(front!=NULL) 
	{ 
		p=front; 
		front=front->link; 
		delete p; 
	} 
	front=rear=NULL; 
} 
/*************************************************************************/ 
CClientSocket::CClientSocket() 
{ 
 
}			 
CClientSocket::~CClientSocket() 
{ 
} 
void CClientSocket::UnInit() 
{ 
	ShutDownSocket(); 
	CloseSocekt(); 
	if(m_hExitEvent != (WSAEVENT)0xcccccccc)WSACloseEvent(m_hExitEvent); 
} 
bool CClientSocket::CreateSocket(SOCKET *pNewSocket,int iSockType) 
{ 
	m_hExitEvent=WSACreateEvent(); 
	WSAResetEvent(m_hExitEvent); 
	 
	return ((*pNewSocket=WSASocket(AF_INET,iSockType,0,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)? 
		false:true; 
} 
bool CClientSocket::BindSocket(SOCKET BindSocket,char *szHostAddr,unsigned short iHostPort) 
{ 
	struct sockaddr_in inAddr; 
	inAddr.sin_addr.S_un.S_addr=inet_addr(szHostAddr); 
	inAddr.sin_family=AF_INET; 
	inAddr.sin_port=htons(iHostPort); 
	return (bind(BindSocket,(PSOCKADDR)&inAddr,sizeof(inAddr))) 
		==SOCKET_ERROR?false:true; 
} 
bool CClientSocket::ShutDownSocket(SOCKET nowSocket) 
{ 
	return shutdown(nowSocket,SD_BOTH)?false:true; 
} 
bool CClientSocket::CloseSocket(SOCKET nowSocket) 
{ 
	return (closesocket(nowSocket)==SOCKET_ERROR)?false:true; 
} 
bool CClientSocket::SendData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time) 
{ 
	WSABUF DataBuf; 
	WSAEVENT hEvents[2]; 
	WSAOVERLAPPED SendOverLapp; 
	DWORD flag; 
 
	hEvents[0]=m_hExitEvent; 
	hEvents[1]=hSendEvent; 
	DataBuf.buf=data; 
	DataBuf.len=len; 
	memset(&SendOverLapp,0,sizeof(WSAOVERLAPPED)); 
	SendOverLapp.hEvent=hSendEvent; 
	flag=0; 
	///////////////////////////////////// 
	int ret; 
	if((ret=WSASend(socket,&DataBuf,1,retlen,flag,&SendOverLapp,NULL))==0) 
		return true; 
	else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING)) 
	{ 
		DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,FALSE,time,FALSE); 
		WSAResetEvent(hSendEvent); 
		if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0) 
		{ 
			if(EventCaused == WAIT_OBJECT_0) 
				SetLastError(CLIENT_FUNERROR); 
			return false; 
		} 
		flag=0; 
		return WSAGetOverlappedResult(socket,&SendOverLapp,retlen,false,&flag)? 
			true:false; 
	} 
	else 
		return false; 
} 
bool CClientSocket::RecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time) 
{ 
	WSABUF DataBuf; 
	WSAEVENT hEvents[2]; 
	WSAOVERLAPPED RecvOverLapp; 
	DWORD flag; 
 
	hEvents[0]=m_hExitEvent; 
	hEvents[1]=hRecvEvent; 
	DataBuf.buf=data; 
	DataBuf.len=len; 
	memset(&RecvOverLapp,0,sizeof(WSAOVERLAPPED)); 
	RecvOverLapp.hEvent=hRecvEvent; 
	flag=0; 
	///////////////////////////////////// 
	int ret; 
	if((ret=WSARecv(socket,&DataBuf,1,retlen,&flag,&RecvOverLapp,NULL))==0) 
		return true; 
	else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING)) 
	{  
		DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,false,time,false); 
		WSAResetEvent(hRecvEvent); 
		if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0) 
		{ 
			if(EventCaused == WAIT_OBJECT_0) 
				SetLastError(CLIENT_FUNERROR); 
			return false; 
		} 
		flag=0; 
		return WSAGetOverlappedResult(socket,&RecvOverLapp,retlen,false,&flag)? 
			true:false; 
	} 
	else 
		return false; 
} 
bool CClientSocket::SendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time) 
{ 
	DWORD left,idx,thisret; 
	left=len; 
	idx=0; 
	int oflag=0; 
	while(left>0) 
	{ 
		if(!SendData(socket,&data[idx],left,&thisret,hSendEvent,time)) 
		{ 
			*retlen=0; 
			return false; 
		} 
		WSAResetEvent(hSendEvent); 
		left-=thisret; 
		idx+=thisret; 
		if(thisret==0) 
		{ 
			oflag++; 
			if(oflag>5) 
				break; 
		} 
	} 
	*retlen=idx; 
	return (idx==len)?true:false; 
} 
bool CClientSocket::RecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time) 
{ 
	DWORD left,idx,thisret; 
	left=len; 
	idx=0; 
	int oflag=0; 
	while(left>0) 
	{ 
		if(!RecvData(socket,&data[idx],left,&thisret,hRecvEvent,time)) 
		{ 
			*retlen=0; 
			return false; 
		} 
		WSAResetEvent(hRecvEvent); 
		left-=thisret; 
		idx+=thisret; 
		if(thisret==0) 
		{ 
			oflag++; 
			if(oflag>5) 
				break; 
		} 
	} 
	*retlen=idx; 
	return (idx==len)?true:false; 
} 
bool CClientSocket::SendMsg(char * data,DWORD len,DWORD *retlen,DWORD time) 
{ 
	WSAEVENT hEvent=WSACreateEvent(); 
	bool bSend=SendDataS(m_Socket,data,len,retlen,hEvent,time); 
	WSACloseEvent(hEvent); 
	return bSend; 
} 
bool CClientSocket::RecvMsg(char * data,DWORD len,DWORD *retlen,DWORD time) 
{	 
	WSAEVENT hEvent=WSACreateEvent(); 
	bool Recv=RecvData(m_Socket,data,len,retlen,hEvent,time); 
	WSACloseEvent(hEvent); 
	return Recv; 
} 
bool CClientSocket::ConnectSocket(char * szDestAddr,unsigned short iDestPort) 
{ 
	struct sockaddr_in inAddr; 
	inAddr.sin_family=AF_INET; 
	inAddr.sin_port=htons(iDestPort); 
	inAddr.sin_addr.S_un.S_addr=inet_addr(szDestAddr); 
	return (connect(m_Socket,(PSOCKADDR)&inAddr,sizeof(inAddr))) 
		    ==SOCKET_ERROR ? false:true; 
} 
 
BOOL CNetClient::isStart() 
{ 
	return IsStart?TRUE:FALSE; 
}