先上图,服务器正在完善中,留作以后博客分享(想增加历史记录缓冲),贴一下EXE下载地址,源码地址在最下面
客户端部分其实实现起来不难,或许最大的难点就在于如何把socket底层的缓冲区调优,以及把解析数据包的逻辑从socket底层操作中解耦出来,以及解析包的算法调优
自从C++11出来以后,C++的很多写法也变得优美起来,本人极力推崇C++11的一些比较稳定优质的方法的,譬如std::function,std::thread等
贴一下主要代码的一些含义
1:自定义的一套帧数据格式解析类,利用包头识别符号,加时间戳,以及尾部校验算法
#pragma once
#include
#include "winsock2.h"
#include "PB_CSocketQueue.h"
class PB_CSocketPackage
{
typedef std::function LogHandler;
struct PB_CSocketPackageHeader
{
char bDataKind;//0xaa 1
char bCheckCode;
short sPacketSize;//2
short sMainCmdID;//2
short sSubCmdID;
time_t unixtime;//0xff 8
PB_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 1
void 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);
return btAryBuffer[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;
}
#pragma once
#ifndef PB_CSOCKETCLIENT_H_
#define PB_CSOCKETCLIENT_H_
#include
#include
#include "winsock2.h"
#include
#include
#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 ClientSocketEventHandler;
typedef std::function 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);
return btAryBuffer[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;
}