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
- VC++ MFC实现一个简易聊天(客户端篇)(逻辑解耦)
- IOCP简易实现(客户端与客户端之间可以聊天)
- 一个简易聊天功能的服务器端和客户端源码
- vc简易网络服务器、客户端实现
- vc简易网络服务器、客户端实现
- 一个简易的聊天程序(Socket)
- [Go]简易聊天实现
- 简易聊天程序教程(四)客户端基本功能
- [MFC]服务端客户端一对一聊天
- 写一个Tomcat+Okhttp实现的聊天websocket聊天框架(一)-- 完成客户端和服务端的通信
- VS2010/MFC:一个简易的恶作剧QQ好友的聊天轰炸机
- MFC用CSocket写简易聊天软件
- Java实现简易QQ聊天
- Socket实现聊天客户端
- MFC简易计算器实现
- 简易抽奖软件逻辑实现
- VC++MFC下实现SOAP服务端和SOAP客户端
- VC++MFC下实现SOAP服务端和SOAP客户端
- Spring学习笔记-WebServive
- [莫队] [分块] [BZOJ3585] mex
- 梯度下降,随机梯度下降,mini-batch梯度下降
- assert()函数用法总结
- 组态软件intouch、ifix、wincc
- VC++ MFC实现一个简易聊天(客户端篇)(逻辑解耦)
- 笔试题5
- Undefined function or variable 'caffe_'
- 【寒假任务】 洛谷1059 明明的随机数
- [BZOJ2882][后缀自动机]工艺
- 哈希表原理
- Markdown-01文本格式化(学习笔记)
- Error:(22, 0) Could not find method android() for argument
- C++建立查找删除节点二叉排序树