VC++ MFC实现一个简易聊天(客户端篇)(逻辑解耦)

来源:互联网 发布:未来计价软件视频 编辑:程序博客网 时间:2024/06/07 03:30

先上图,服务器正在完善中,留作以后博客分享(想增加历史记录缓冲),贴一下EXE下载地址,源码地址在最下面


客户端部分其实实现起来不难,或许最大的难点就在于如何把socket底层的缓冲区调优,以及把解析数据包的逻辑从socket底层操作中解耦出来,以及解析包的算法调优

自从C++11出来以后,C++的很多写法也变得优美起来,本人极力推崇C++11的一些比较稳定优质的方法的,譬如std::function,std::thread等


贴一下主要代码的一些含义

1:自定义的一套帧数据格式解析类,利用包头识别符号,加时间戳,以及尾部校验算法

#pragma once#include  <iostream>#include  "winsock2.h"#include "PB_CSocketQueue.h"class PB_CSocketPackage{typedef std::function<void(const char * msg)>  LogHandler;struct PB_CSocketPackageHeader{char bDataKind;//0xaa 1char bCheckCode;short sPacketSize;//2short sMainCmdID;//2short sSubCmdID;time_t unixtime;//0xff  8PB_CSocketPackageHeader(short _sPacketSize, short _sMainCmdID, short _sSubCmdID):bDataKind(0xaa), bCheckCode(0xff){unixtime = time(NULL);sPacketSize = _sPacketSize;sMainCmdID = _sMainCmdID;sSubCmdID = _sSubCmdID;}};public:PB_CSocketPackage();~PB_CSocketPackage();#define HEAD_LEN 16#define FOOT_LEN 1void MakePacket(const std::string str, short mainCMD, short subCMD);bool Analysis(PB_CSocketQueue &queue);//LogHandler loghander;std::string framedata;char *  packetBuff;int  packetSize;char *  packetBodyBuff;int  packetBodySize;PB_CSocketPackageHeader packageheader;};
#include "PB_CSocketPackage.h"static char GetSum(char *btAryBuffer, int nLen){char btSum = 0x00;for (int nloop = 0; nloop < nLen; nloop++){btSum += btAryBuffer[nloop];}return ((~btSum) + 1)*nLen;}static bool CheckBuff(char *btAryBuffer, int nLen){char c = GetSum(btAryBuffer, nLen - FOOT_LEN);returnbtAryBuffer[nLen - FOOT_LEN] == c;}PB_CSocketPackage::PB_CSocketPackage() :packageheader(0, 0, 0){packetBuff = NULL;}PB_CSocketPackage::~PB_CSocketPackage(){if (packetBuff != NULL){delete packetBuff;packetBuff = NULL;}}void PB_CSocketPackage::MakePacket(const std::string str, short mainCMD, short subCMD){/*bool flag = CheckCRC16(testarr, 24);if (flag){OutputDebugString(TEXT("OK"));}else{OutputDebugString(TEXT("ERROR"));}*/packageheader.sMainCmdID = htons(mainCMD);packageheader.sSubCmdID = htons(subCMD);packageheader.unixtime = htonll(packageheader.unixtime);packageheader.unixtime = 0;if (packetBuff != NULL){delete packetBuff;packetBuff = NULL;}packetBodySize = str.size();packetSize = HEAD_LEN + packetBodySize + FOOT_LEN;packageheader.sPacketSize = htons(packetSize);//确定包总长度packetBuff = new char[packetSize];char  *p = packetBuff;memcpy(p, &packageheader, HEAD_LEN); p = p + HEAD_LEN;memcpy(p, str.data(), packetBodySize); p = p + packetBodySize;char  g= GetSum(packetBuff, packetSize - FOOT_LEN);//short g = htons(ss);memcpy(p, &g, FOOT_LEN);}bool PB_CSocketPackage::Analysis(PB_CSocketQueue &queue){int len = queue.length();if (len < HEAD_LEN)return false;int topN = queue.indexof(0xaa);if (topN > 0){queue.removeTop(topN);//移除冗余len = queue.length();}if (len > HEAD_LEN)//假如已经够一个头的长度了,那么马上解析头{queue.copyTo((char*)&packageheader, HEAD_LEN);packageheader.sMainCmdID = htons(packageheader.sMainCmdID);packageheader.sSubCmdID = htons(packageheader.sSubCmdID);packageheader.sPacketSize = htons(packageheader.sPacketSize);packageheader.unixtime = htonll(packageheader.unixtime);int packetSize = packageheader.sPacketSize;if (len >= packetSize){if (packetBuff != NULL)delete packetBuff;packetBuff = new char[packetSize];queue.copyTo(packetBuff, packetSize);//一帧数据全部拷贝走packetBodySize = packetSize - HEAD_LEN - FOOT_LEN;packetBodyBuff = packetBuff + HEAD_LEN;//数据指向//CRC校验数据queue.removeTop(packetSize);//移除一帧数据(不关是不是废包)bool flag = CheckBuff(packetBuff, packetSize);framedata = "";if (flag)framedata.append(packetBodyBuff, packetBodySize);return flag;//return true;}}return false;}

2:PB_CSocketClient客户端类,这里就利用我上一篇博客自制的缓冲区类

#pragma once#ifndef  PB_CSOCKETCLIENT_H_#define PB_CSOCKETCLIENT_H_#include <iostream>#include <functional>#include "winsock2.h"#include <vector>#include <mutex>#include "PB_CSocketQueue.h"#pragma comment(lib, "ws2_32.lib")class PB_CSocketClientException{public:int Code;std::string Msg;PB_CSocketClientException(const char * msg, int code = -1){Msg = msg;Code = code;}};enum class PB_CSocketClient_EVENT{ClientConnect = 100,ClientDisConnect,SocketError};class PB_CSocketClient{typedef std::function<void(const char * msg, PB_CSocketClient_EVENT)>  ClientSocketEventHandler;typedef std::function<int(PB_CSocketQueue&)> AnalysisHandler;public:PB_CSocketClient();~PB_CSocketClient();void SetSocketHandle(SOCKET _csocket);int Send(const char* pBuf, int len);int Receive();//纯客户端方法bool CConnect(const char *ip, int port);void CStartReceiveSync(AnalysisHandler DataReceived);bool IsConnected() const{return isConnected;}void SetConnected(bool val) {isConnected = val;}std::string GetClientIPPort();void SClose();bool SShutDown();PB_CSocketQueue m_queue;SOCKET csocket;sockaddr_in clientaddr;sockaddr_in serverAddress;ClientSocketEventHandler EvenHandler;std::string logstr;void * PTRAnalysisClass;private:bool isConnected;//链接状态};#endif


#include "PB_CSocketPackage.h"static char GetSum(char *btAryBuffer, int nLen){char btSum = 0x00;for (int nloop = 0; nloop < nLen; nloop++){btSum += btAryBuffer[nloop];}return ((~btSum) + 1)*nLen;}static bool CheckBuff(char *btAryBuffer, int nLen){char c = GetSum(btAryBuffer, nLen - FOOT_LEN);returnbtAryBuffer[nLen - FOOT_LEN] == c;}PB_CSocketPackage::PB_CSocketPackage() :packageheader(0, 0, 0){packetBuff = NULL;}PB_CSocketPackage::~PB_CSocketPackage(){if (packetBuff != NULL){delete packetBuff;packetBuff = NULL;}}void PB_CSocketPackage::MakePacket(const std::string str, short mainCMD, short subCMD){/*bool flag = CheckCRC16(testarr, 24);if (flag){OutputDebugString(TEXT("OK"));}else{OutputDebugString(TEXT("ERROR"));}*/packageheader.sMainCmdID = htons(mainCMD);packageheader.sSubCmdID = htons(subCMD);packageheader.unixtime = htonll(packageheader.unixtime);packageheader.unixtime = 0;if (packetBuff != NULL){delete packetBuff;packetBuff = NULL;}packetBodySize = str.size();packetSize = HEAD_LEN + packetBodySize + FOOT_LEN;packageheader.sPacketSize = htons(packetSize);//确定包总长度packetBuff = new char[packetSize];char  *p = packetBuff;memcpy(p, &packageheader, HEAD_LEN); p = p + HEAD_LEN;memcpy(p, str.data(), packetBodySize); p = p + packetBodySize;char  g= GetSum(packetBuff, packetSize - FOOT_LEN);//short g = htons(ss);memcpy(p, &g, FOOT_LEN);}bool PB_CSocketPackage::Analysis(PB_CSocketQueue &queue){int len = queue.length();if (len < HEAD_LEN)return false;int topN = queue.indexof(0xaa);if (topN > 0){queue.removeTop(topN);//移除冗余len = queue.length();}if (len > HEAD_LEN)//假如已经够一个头的长度了,那么马上解析头{queue.copyTo((char*)&packageheader, HEAD_LEN);packageheader.sMainCmdID = htons(packageheader.sMainCmdID);packageheader.sSubCmdID = htons(packageheader.sSubCmdID);packageheader.sPacketSize = htons(packageheader.sPacketSize);packageheader.unixtime = htonll(packageheader.unixtime);int packetSize = packageheader.sPacketSize;if (len >= packetSize){if (packetBuff != NULL)delete packetBuff;packetBuff = new char[packetSize];queue.copyTo(packetBuff, packetSize);//一帧数据全部拷贝走packetBodySize = packetSize - HEAD_LEN - FOOT_LEN;packetBodyBuff = packetBuff + HEAD_LEN;//数据指向//CRC校验数据queue.removeTop(packetSize);//移除一帧数据(不关是不是废包)bool flag = CheckBuff(packetBuff, packetSize);framedata = "";if (flag)framedata.append(packetBodyBuff, packetBodySize);return flag;//return true;}}return false;}

附上:源代码下载地址





0 0
原创粉丝点击