接上面Server部分
五、DealMsg.h
/********************************************************************
File name: DealMsg.h
Author: lieyingshengbao
Version: 1.0
Date: 2013-1-6
Description: 本文件提供处理消息的类
Others: 本类型使用C++定义
Function List: 请参见正文
History: 修改历史记录列表,每条修改记录应包括修改日期、修改者及修改内容简述
1. Date:
Author:
Modification:
2. ...
*********************************************************************/
#ifndef _DEALMSG_H_
#define _DEALMSG_H_
#include "ThreadPoolBase.h"
#include "PubDefine.h"
#include <WinSock2.h>
#include <map>
using std::map;
class CMsg
{
public:
SOCKET *m_SockConn;
BYTE cArryMsg[MSGBLOCKLEN+sizeof(CommonHead_S)]; //存放接收到的消息内容
};
class CDealMsg : public CThreadPoolBase<CMsg>
{
public:
CDealMsg(int nDealThreadNum):CThreadPoolBase(nDealThreadNum)
{
//创建用户信息的链表节点
m_pUsrInfoList = new UsrInfoNode_S;
memset(m_pUsrInfoList->cArryUsr, 0, USRINFONODELEN);
m_pUsrInfoList->pNodeNext = NULL;
m_pUsrInfoList->pNodePrevious = NULL;
m_pUsrInfoHead = m_pUsrInfoList;
//先创建两个节点测试
CString s1 = "local1:1.2.3.4:23456";
CString s2 = "local2:2.3.4.5:45678";
memcpy(m_pUsrInfoList->cArryUsr, s1.GetBuffer(s1.GetLength()), s1.GetLength());
m_pUsrInfoNew = new UsrInfoNode_S;
memset(m_pUsrInfoNew, 0, USRINFONODELEN);
m_pUsrInfoNew->pNodeNext = NULL;
m_pUsrInfoNew->pNodePrevious = NULL;
m_pUsrInfoList->pNodeNext = m_pUsrInfoNew;
m_pUsrInfoNew->pNodePrevious = m_pUsrInfoList;
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
//memset(m_pUsrInfoList, 0, sizeof(UsrInfoNode_S)); 杜绝这种暴力编码方式
memcpy(m_pUsrInfoList->cArryUsr, s2.GetBuffer(s2.GetLength()), s2.GetLength());
m_pUsrInfoNew = new UsrInfoNode_S;
memset(m_pUsrInfoNew, 0, USRINFONODELEN);
m_pUsrInfoNew->pNodeNext = NULL;
m_pUsrInfoNew->pNodePrevious = NULL;
m_pUsrInfoList->pNodeNext = m_pUsrInfoNew;
m_pUsrInfoNew->pNodePrevious = m_pUsrInfoList;
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
}
~CDealMsg()
{
//释放链表
if (NULL != m_pUsrInfoHead)
{
m_pUsrInfoList = m_pUsrInfoHead;
while (m_pUsrInfoList->pNodeNext != NULL)
{
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
delete m_pUsrInfoHead;
m_pUsrInfoHead = m_pUsrInfoList;
}
delete m_pUsrInfoList;
m_pUsrInfoList = NULL;
m_pUsrInfoHead = NULL;
}
}
//重写基类中纯虚方法
void DealMsg(CMsg* pMsg);
private:
//获取消息的CommandId
int GetMsgCommandId(BYTE *pBuffer);
//获取消息序列
int GetMsgSequence(BYTE *pBuffer);
//处理获取用户信息的请求消息
int GetUsrListRspFunction(SOCKET SockTemp, int nSequenceNum);
//将用户信息加入链表中保存
void AddClientToList(BYTE *pMsgContent);
//获取客户IP信息,删掉List中用户信息
void GetClientIPToDeleteList(BYTE *pMsgContent, CString &sIP);
//处理用户刷新消息
int DealUsrRefreshMsg(SOCKET SockTemp, int nSequenceNum);
//转发聊天消息
int DealChatMsg(BYTE* pMsg);
public:
//关闭Client对应的socket
void CloseSockConn(CString sClientIP);
//回复上线的请求消息,未用到
//int OnLineRspFunction(SOCKET SockTemp, int nSequenceNum);
private:
UsrInfoNode_S* m_pUsrInfoHead;
UsrInfoNode_S* m_pUsrInfoList;
UsrInfoNode_S* m_pUsrInfoNew; //为了专门new链表节点
};
#endif
六、DealMsg.cpp
#include "stdafx.h"
#include "DealMsg.h"
//为了方便处理消息过程去处理(尽量不用全局变量)
extern CString g_sClientIP;
extern int g_nClientPort;
extern map<CString, SOCKET*> g_mapIPPort_Sock;
extern vector<SOCKET*> g_vecSocket;
/*************************************************************************
* Function name : GetUsrListRspFunction
* description : 处理获取用户列表信息的请求,返回到Client端,在list中显示
* input : CMsg* pMsg
* output : 无
* return : 无
*************************************************************************/
int CDealMsg::GetUsrListRspFunction(SOCKET SockTemp, int nSequenceNum)
{
GetOnlineUsrInfo_S GetUsrInfoObj;
GetUsrInfoObj.Head.nCommandId = htonl(GetUsrListRsp);
GetUsrInfoObj.Head.nSequenceNum = htonl(nSequenceNum);
CString sSumReturn("");
m_pUsrInfoList = m_pUsrInfoHead;
while (m_pUsrInfoList->pNodeNext != NULL)
{
CString sTempStr = m_pUsrInfoList->cArryUsr;
//CString sPort;
//sPort.Format("%d", g_nClientPort);
//CString sUsrIpPort = g_sClientIP + ":" + sPort;
//int nPos = sTempStr.Find(sUsrIpPort);
//if (-1 == nPos) //未找到,则返回。即每次只是返回其他用户信息,不返回Client本身的
/*{
sSumReturn += (sTempStr + ";");
}*/
//完全下发,交给客户端自己去过滤
sSumReturn += (sTempStr + ";");
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
}
sSumReturn.TrimRight(";");
memset(GetUsrInfoObj.cArryUsrInfo, 0, USRINFOLEN);
memcpy(GetUsrInfoObj.cArryUsrInfo, sSumReturn.GetBuffer(sSumReturn.GetLength()), sSumReturn.GetLength());
GetUsrInfoObj.Head.nMsgTotalLen = htonl(sizeof(GetOnlineUsrInfo_S));
if (SOCKET_ERROR == send(SockTemp, (char*)&GetUsrInfoObj, sizeof(GetOnlineUsrInfo_S), 0))
{
AfxMessageBox(_T("CDealMsg::GetUsrListRspFunction: Failed to send Msg"));
return Failed;
}
return Success;
}
/*************************************************************************
* Function name : AddClientToList
* description : 向链表中加入Client信息
* input : CString sLocalName
* output : 无
* return : 无
*************************************************************************/
void CDealMsg::AddClientToList(BYTE *pMsgContent)
{
CString sClientLocalName = (char*)pMsgContent;
CString sPort;
sPort.Format("%d", g_nClientPort);
CString sClientInfo = sClientLocalName + ":" + g_sClientIP + ":" + sPort;
memcpy(m_pUsrInfoList->cArryUsr, sClientInfo.GetBuffer(sClientInfo.GetLength()), sClientInfo.GetLength());
m_pUsrInfoNew = new UsrInfoNode_S;
memset(m_pUsrInfoNew, 0, USRINFONODELEN);
m_pUsrInfoNew->pNodeNext = NULL;
m_pUsrInfoNew->pNodePrevious = NULL;
m_pUsrInfoList->pNodeNext = m_pUsrInfoNew;
m_pUsrInfoNew->pNodePrevious = m_pUsrInfoList;
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
return;
}
/*************************************************************************
* Function name : GetClientIPToDeleteList
* description : 根据获取的客户端IP,删除链表中对应的用户节点。双向链表删除
* input : BYTE *pMsgContent, CString &sIP
* output : sIP值
* return : 无
*************************************************************************/
void CDealMsg::GetClientIPToDeleteList(BYTE *pMsgContent, CString &sIP)
{
sIP = (char*)pMsgContent;
m_pUsrInfoList = m_pUsrInfoHead;
//当m_pUsrInfoHead的Client信息中IP与sIP相同,特殊处理
CString sClientIP = m_pUsrInfoHead->cArryUsr;
if (-1 != sClientIP.Find(sIP))
{
m_pUsrInfoHead = m_pUsrInfoHead->pNodeNext;
delete m_pUsrInfoList;
m_pUsrInfoList = m_pUsrInfoHead;
return;
}
//Head不相同
while (m_pUsrInfoList->pNodeNext != NULL)
{
CString sClientInfo = m_pUsrInfoList->cArryUsr;
if (-1 != sClientInfo.Find(sIP))
{
m_pUsrInfoList->pNodePrevious->pNodeNext = m_pUsrInfoList->pNodeNext;
m_pUsrInfoList->pNodeNext->pNodePrevious = m_pUsrInfoList->pNodePrevious;
delete m_pUsrInfoList;
m_pUsrInfoList = m_pUsrInfoHead;
return;
}
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
}
return;
}
/*************************************************************************
* Function name : DeleteSockFromVector
* description : 将socket从全局的g_vecSocket删除
* input : SOCKET sock
* output : 无
* return : 无
*************************************************************************/
void DeleteSockFromVector(SOCKET sock)
{
vector<SOCKET*>::iterator ItSock;
for (ItSock=g_vecSocket.begin(); ItSock!=g_vecSocket.end(); ++ItSock)
{
if (sock == *(*ItSock))
{
g_vecSocket.erase(ItSock);
return;
}
else
continue;
}
return;
}
/*************************************************************************
* Function name : CloseSockConn
* description : 关闭服务端与客户端对应的socket
* input : CMsg* pMsg
* output : 无
* return : 无
*************************************************************************/
void CDealMsg::CloseSockConn(CString sClientIP)
{
map<CString, SOCKET*>::iterator ItSock;
for (ItSock=g_mapIPPort_Sock.begin(); ItSock!=g_mapIPPort_Sock.end(); ++ItSock)
{
if (-1 != ItSock->first.Find(sClientIP))
{
//删掉vector中的Socket
DeleteSockFromVector(*(ItSock->second));
closesocket(*(ItSock->second));
*(ItSock->second) = INVALID_SOCKET;
delete ItSock->second;
ItSock->second = NULL;
g_mapIPPort_Sock.erase(ItSock);
return;
}
else
continue;
}
return;
}
/*************************************************************************
* Function name : DealUsrRefreshMsg
* description : 处理用户刷新消息,返回在线客户端信息
* input : SOCKET SockTemp, int nSequenceNum
* output : 无
* return : 无
*************************************************************************/
int CDealMsg::DealUsrRefreshMsg(SOCKET SockTemp, int nSequenceNum)
{
RefreshMsg_S RefreshMsgObj;
RefreshMsgObj.Head.nSequenceNum = htonl(nSequenceNum);
RefreshMsgObj.Head.nCommandId = htonl(RefreshRsp);
memset(RefreshMsgObj.cArryRefresh, 0, USRINFOLEN);
CString sSumReturn("");
m_pUsrInfoList = m_pUsrInfoHead;
while (m_pUsrInfoList->pNodeNext != NULL)
{
CString sTempStr = m_pUsrInfoList->cArryUsr;
sSumReturn += (sTempStr + ";");
m_pUsrInfoList = m_pUsrInfoList->pNodeNext;
}
sSumReturn.TrimRight(";");
memcpy(RefreshMsgObj.cArryRefresh, sSumReturn.GetBuffer(sSumReturn.GetLength()), sSumReturn.GetLength());
RefreshMsgObj.Head.nMsgTotalLen = htonl(sizeof(RefreshMsg_S));
if (SOCKET_ERROR == send(SockTemp, (char*)&RefreshMsgObj, sizeof(GetOnlineUsrInfo_S), 0))
{
AfxMessageBox(_T("CDealMsg::DealUsrRefreshMsg: Failed to send Msg"));
return Failed;
}
return Success;
}
/*************************************************************************
* Function name : DealChatMsg
* description : 处理聊天消息.收到Client1发的消息,发给Client2.
服务端只是负责转发消息功能。只是send即可
* input : BYTE* pMsg
* output : 无
* return : 无
*************************************************************************/
int CDealMsg::DealChatMsg(BYTE* pMsg)
{
SOCKET *pSock = NULL;
ChatMsg_S *pChatMsg = (ChatMsg_S*)pMsg;
CString sDestIPPORT = pChatMsg->cArryDestInfo;
//CString sMsg = pChatMsg->cArryMsg;
map<CString, SOCKET*>::iterator ItSock;
for (ItSock=g_mapIPPort_Sock.begin(); ItSock!=g_mapIPPort_Sock.end(); ++ItSock)
{
CString sInfo = ItSock->first;
if (!sInfo.Compare(sDestIPPORT))
{
pSock = ItSock->second;
}
}
send(*pSock, (char*)pMsg, sizeof(ChatMsg_S), 0);
return 0;
}
/*************************************************************************
* Function name : DealMsg
* description : 重写基类中的纯虚方法,具体处理消息
* input : CMsg* pMsg
* output : 无
* return : 无
*************************************************************************/
void CDealMsg::DealMsg(CMsg* pMsg)
{
//解析消息
int nCommandId = GetMsgCommandId(pMsg->cArryMsg);
int nSequenceNum = GetMsgSequence(pMsg->cArryMsg);
SOCKET SockTemp = *(pMsg->m_SockConn);
BYTE *pMsgBegin = pMsg->cArryMsg;
BYTE *pMsgContent = pMsgBegin + sizeof(CommonHead_S);
CString sClientIP;
switch (nCommandId)
{
case GetUsrListReq: //获取用户列表信息
AddClientToList(pMsgContent); //将用户信息加入List表中
GetUsrListRspFunction(SockTemp, nSequenceNum);
break;
case HeartBeatReq: //心跳消息
break;
case ChatMsgReq: //聊天消息
DealChatMsg(pMsgBegin);
break;
case RefreshReq: //用户上线消息未用到
DealUsrRefreshMsg(SockTemp, nSequenceNum);
break;
case OffLineReq: //用户下线消息
//将用户信息从链表中去掉+关闭Client相应套接字,删掉socket空间(从map中取出来。延时关闭)
GetClientIPToDeleteList(pMsgContent, sClientIP);
CloseSockConn(sClientIP); //关闭ip对应的socket
break;
default:
break;
}
//将accept产生的socket保存到map中,等待客户端发送的下线消息时候关闭。
/*if (INVALID_SOCKET != *(pMsg->m_SockConn))
{
closesocket(*(pMsg->m_SockConn));
delete pMsg->m_SockConn;
pMsg->m_SockConn = NULL;
}*/
if (pMsg)
{
delete pMsg;
pMsg = NULL;
}
return;
}
/*************************************************************************
* Function name : GetMsgCommandId
* description : 解析消息,获取消息的CommandId
* input : BYTE *pBuffer
* output : 无
* return : 无
*************************************************************************/
int CDealMsg::GetMsgCommandId(BYTE *pBuffer)
{
CommonHead_S *pHead = (CommonHead_S*)pBuffer;
int nCommandId = ntohl(pHead->nCommandId);
return nCommandId;
}
/*************************************************************************
* Function name : GetMsgSequence
* description : 解析消息,获取消息的Sequence
* input : BYTE *pBuffer
* output : 无
* return : 无
*************************************************************************/
int CDealMsg::GetMsgSequence(BYTE *pBuffer)
{
CommonHead_S *pHead = (CommonHead_S*)pBuffer;
int nSequenceNum = ntohl(pHead->nSequenceNum);
return nSequenceNum;
}
七、
CRecvMsg m_RecvObj; 构造函数中m_RecvObj(5)
启动监听:m_RecvObj.CreateSocketThread();
取消:m_RecvObj.m_bQuitThread = true;
Sleep(5000);
OnCancel();