简单聊天工具,未添加传输文件的过程,道理类似

接上面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();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值