客户端类
// 客户端类
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;
}