学习笔记二,vc++创建多线程服务器(四)

客户端类

// 客户端类
class CClient
{
public:
	CClient(const SOCKET sClient,const SOCKADDR_IN &addrClient);
	virtual ~CClient();
public:
	BOOL StartRuning(void);
	void HandleData(const char* pExpr);
	BOOL IsConning(void){
		return m_bConning;
	}
	void DisConning(void){
		m_bConning = FALSE;
	}
	
	BOOL IsExit(void){
		return m_bExit;
	}
public:
	static DWORD __stdcall RecvDataThread(void* pParam); //接收客户端数据
	static DWORD __stdcall SendDataThread(void* pParam); //接向客户端发送数据
private:
	CClient();
private:
	SOCKET m_socket;
	SOCKADDR_IN  m_addr;
	DATABUF m_data;
	HANDLE m_hEvent;
	HANDLE m_hThreadSend;
	HANDLE m_hThreadRecv;
	CRITICAL_SECTION m_cs;
	BOOL m_bConning;
	BOOL m_bExit;
};
void CClient::CClient(const SOCKET sClient,const SOCKADDR_IN &addrClient)
{
	//初始化变量
	m_hThreadRecv = NULL;
	m_hThreadSend = NULL;
	m_socket = sClient;
	m_bConning = FALSE;
	m_bExit = FALSE;
	memset(m_data.buf,0,MAX_NUM_BUF);
	m_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	InitializeCriticalSection(&m_cs);	
}

void CClient::~CClient()
{
	closesocket(m_socket);
	m_socket = INVALID_SOCKET;
	DeleteCriticalSection(&m_cs);
	CloseHandle(m_hEvent);
}
void CClient::RecvDataThread(void* pParam)
{
	CClient *pClient = (CClient*)pParam;
	int reVal;
	char temp[MAX_NUM_BUF];
	
	memset(temp,0,MAX_NUM_BUF);
	
	for(;pClient->m_bConning;)
	{
		reVal = recv(pClient->m_socket,temp,MAX_NUM_BUF,0);
		if(SOCKET_ERROR == reVal)
		{
			int nErrCode = WSAGetLastError();
			if(nErrcode == WSAEWOULDBLOCK)//无法立即完成一个非阻塞式套接字操作
			{
				continue;
			}
			else if(WSAENETDOWN == nErrcode || WSAETIMEDOUT == nErrcode || WSAECONNRESET == nErrcode)
			{
				break;
			}		
		}
		//客户端关闭了连接
		if(reVal == 0)
		{
			break;
		}
		//收到数据
		if(reVal > HEADERLEN)
		{
			pClient->HandleData(temp);	
			SetEvent(pClient->m_hEvent);
			memset(temp, 0, MAX_NUM_BUF);
		}
		
		Sleep(TIMEFOR_THREAD_CLIENT);	
	}
	pClient->m_bConning = FALSE;
	SetEvent(pClient->m_hEvent);
	return 0;
}

//计算数据
//数据包类型---包含包头和数据两部分
#define EXPRESSION	'E'		//算术表达式
#define BYEBYE		'B'		//消息Byebye,byebye,OK
#define HEADERLEN	(sizeof(hdr))	//头长度

//数据包头结构,该结构在win32下午4byte
typedef struct _head
{
	char type;				//类型
	usigned short len;		//数据包的长度(包括头的长度)
}hdr,*phdr;

//数据包中的数据结构
typedef struct _data
{
	char buf[MAX_NUM_BUF];
}DATABUF,*pDataBuf;			//数据



//计算表达式,打包数据
void CClient::HandleData(const char* pExpr)
{
	memset(m_data.buf,0,MAX_NUM_BUF);		//清空m_data
	//如果是“byebye”或者“Byebye”
	if(BYEBYE == ((phdr)pExpr)->type)
	{
		EnterCriticalSection(&m_cs);
		phdr pHeaderSend = (phdr)m_data.buf;						//发送的数据
		pHeaderSend->type = BYEBYE;									//单词类型
		pHeaderSend->len = HEADERLEN + srelen("OK");				//数据包长度
		memcpy(m_data.buf + HEADERLEN, "OK", strlen("OK"));			//复制数据到m_data
		LeaveCriticalSection(&m_cs);
	}
	else//算数表达式
	{
		int nFirNum;
		int nSecNum;
		char cOper;
		int nResult;
		//格式化读入数据
		sscanf(pExpr + HEADERLEN, "%d%c%d", &nFirNum,&cOper,&nSecNum);
		
		//计算
		switch(cOper)
		{
		case "+":
			{
				nResult = nFirNum + nSecNum;
				break;
			}
		case "-":
			{
				nResult = nFirNum - nSecNum;
				break;
			}
		case "*":
			{
				nResult = nFirNum * nSecNum;
				break;
			}
		case "/":
			{
				if(ZERO == nSecNum)
				{
					nResult = INVALID_NUM;
				}
				else
				{
					nResult = nFirNum / nSecNum;
				}
				break;
			}
		default:
			nResult = INVALID_OPERATOR;
			break;
		}
		
		//将算数表达式和计算的结果写入字符数组中
		char temp[MAX_NUM_BUF];
		char cEqu = "=";
		sprintf(temp, "%d%c%d%c%d",nFirNum,cOper,nSecNum);
		
		//打包数据
		EnterCriticalSection(&m_cs);
		phdr pHeaderSend = (phdr)m_data.buf;
		pHeaderSend->type = EXPRESSION;
		pHeaderSend->len = HEADERLEN + strlen(temp);
		memcpy(m_data.buf + HEADERLEN, temp, strlen(temp));
		LeaveCriticalSection(&m_cs);
	}
}


//发送数据
DWORD CClient::SendDataThread(void* pParam)
{
	CClientm *pClient = (CClient*)pParam;
	
	for(;pClient -> m_bConning;)
	{
		//收到事件通知
		if(WAIT_OBJECT_0 == WaitforSingleObject(pClient->hEvent,INFINITE))
		{
			//当客户端的连接断开时,接收数据线程先退出,然后该线程退出,并设置退出标识
			if(!pClient->m_bConning)
			{
				pClient->m_bExit = TRUE;
				break;
			}
			
			//进入临界区
			EnterCriticalSection(&pClient->ms);
			//发送数据
			phdr pHeader = (phdr)pClient->m_data.buf;
			int nSendlen = pHeader->len;
			
			int val = send(pClient->m_socket,pClient->m_data.buf,nSendlen,0);
			//返回错误
			if(SOCKET_ERROR == val)
			{
				int nErrCode = WSAGetLastError();
				if(nErrCode == WSAEWOULDBLOCK)
				{
					continue;
				}
				else if(WSAENETDOWN == nErrcode || WSAETIMEDOUT == nErrcode || WSAECONNRESET == nErrcode) //客户端关闭连接
				{
					//离开临界区
					LeaveCriticalSection(&pClient->m_cs);
					pClient->m_bConning = FALSE;
					pClient->m_bExit = TRUE;
					break;
				}
				else
				{
					//离开临界区
					LeaveCriticalSection(&pClient->m_cs);
					pClient->m_bConning = FALSE;
					pClient->m_bExit = TRUE;
					break;
				}	
			}
			//成功发送数据
			//离开临界区
			LeaveCriticalSection(&pClient->m_cs);
			//设置事件为无信号状态
			ResetEvent(&pClient->m_hEvent);
		}
	}
	
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值