【包类CPacket】

包类(处理网络传输中的数据包)

这段代码定义了一个名为 CPacket 的类,用于表示和操作网络数据包。这个类的设计旨在简化封包和解包操作,使得数据包在网络传输中更易于处理。下面是对代码的详细解释:

1. 成员变量

WORD sHead;        // 包头,固定值 0xFEFF
DWORD nLength;     // 包的长度,包括命令、数据和校验和
WORD sCmd;         // 控制命令,用于标识数据包的类型或功能
std::string strData; // 包的数据部分,可能包含可变长度的数据
WORD sSum;         // 校验和,用于验证数据包的完整性
std::string strOut;// 完整的包数据,包含包头、长度、命令、数据和校验和
  • sHead: 包头,固定为 0xFEFF,用于标识数据包的开始。
  • nLength: 表示数据包的长度,从命令开始到校验和结束的总长度。
  • sCmd: 控制命令,用于标识包的类型或执行的操作。
  • strData: 数据包的主体部分,可以包含任意的二进制数据。
  • sSum: 校验和,用于数据完整性的验证。通过将数据包的所有字节相加(模 0xFFFF)得到。
  • strOut: 整个包的数据,包括所有部分,作为一个完整的二进制序列。

2. 构造函数

默认构造函数
CPacket() :sHead(0), nLength(0), sCmd(0), sSum(0) {}
  • 默认构造函数:初始化所有成员变量为零。这使得创建一个空的 CPacket 对象。
参数化构造函数
CPacket(WORD nCmd, const BYTE* pData, size_t nSize) {
    sHead = 0xFEFF;
    nLength = nSize + 4;
    sCmd = nCmd;
    if (nSize > 0) {
        strData.resize(nSize);
        memcpy((void*)strData.c_str(), pData, nSize);
    } else {
        strData.clear();
    }
    sSum = 0;
    for (size_t j = 0; j < strData.size(); j++) {
        sSum += BYTE(strData[j]) & 0xFF;
    }
}
  • 参数化构造函数:接受命令 (nCmd)、数据 (pData)、数据大小 (nSize) 作为参数,构建一个包含这些信息的数据包。
  • 设置包头sHead 被设置为固定值 0xFEFF。
  • 计算并设置包长度nLength 为数据大小加上命令和校验和的长度(共 4 字节)。
  • 拷贝数据:如果数据存在(nSize > 0),则将其拷贝到 strData 中;否则,清空 strData
  • 计算校验和:通过累加 strData 中每个字节的值来计算 sSum
拷贝构造函数
CPacket(const CPacket& pack) {
    sHead = pack.sHead;
    nLength = pack.nLength;
    sCmd = pack.sCmd;
    strData = pack.strData;
    sSum = pack.sSum;
}
  • 拷贝构造函数:通过复制另一个 CPacket 对象的所有成员变量来构造新对象。
解包构造函数
CPacket(const BYTE* pData, size_t& nSize) {
    size_t i = 0;
    for (; i < nSize; i++) {
        if (*(WORD*)(pData + i) == 0xFEFF) {
            sHead = *(WORD*)(pData + i);
            i += 2;
            break;
        }
    }
    if (i + 4 + 2 + 2 > nSize) {
        nSize = 0;
        return;
    }
    nLength = *(DWORD*)(pData + i); i += 4;
    if (nLength + i > nSize) {
        nSize = 0;
        return;
    }
    sCmd = *(WORD*)(pData + i); i += 2;
    if (nLength > 4) {
        strData.resize(nLength - 2 - 2);
        memcpy((void*)strData.c_str(), pData + i, nLength - 4);
        i += nLength - 4;
    }
    sSum = *(WORD*)(pData + i); i += 2;
    WORD sum = 0;
    for (size_t j = 0; j < strData.size(); j++) {
        sum += BYTE(strData[j]) & 0xFF;
    }
    if (sum == sSum) {
        nSize = i;
        return;
    }
    nSize = 0;
}
  • 解包构造函数:从一个原始字节数组(pData)中解析出数据包,如果解析成功,更新 nSize 以反映解析的字节数。
  • 找到包头:在数据中查找 0xFEFF,找到后将 sHead 设置为该值。
  • 检查数据完整性:通过检查长度、命令、数据和校验和,确保数据包完整。
  • 验证校验和:计算 strData 的校验和,并与接收到的 sSum 进行比较,若匹配则认为数据包有效。

3. 析构函数

~CPacket() {}
  • 析构函数:没有执行特别的清理工作,因为使用的主要是自动管理内存的 std::string

4. 运算符重载

CPacket& operator=(const CPacket& pack) {
    if (this != &pack) {
        sHead = pack.sHead;
        nLength = pack.nLength;
        sCmd = pack.sCmd;
        strData = pack.strData;
        sSum = pack.sSum;
    }
    return *this;
}
  • 赋值运算符:重载赋值运算符,使得可以将一个 CPacket 对象赋值给另一个对象。通过检查自赋值,确保安全。

5. 辅助方法

Size() 方法
int Size() {
    return nLength + 6;
}
  • 计算包的大小:返回包的总长度,包括包头(2字节)、长度字段(4字节)、命令、数据和校验和。
Data() 方法
const char* Data() {
    strOut.resize(nLength + 6);
    BYTE* pData = (BYTE*)strOut.c_str();
    *(WORD*)pData = sHead; pData += 2;
    *(DWORD*)(pData) = nLength; pData += 4;
    *(WORD*)pData = sCmd; pData += 2;
    memcpy(pData, strData.c_str(), strData.size()); pData += strData.size();
    *(WORD*)pData = sSum;
    return strOut.c_str();
}
  • 获取完整包数据:返回包含整个包数据的指针(char* 类型),可直接用于发送或其他处理。这个方法将数据打包成完整的数据包格式,并存储在 strOut 中。

6. 关联逻辑

  • 封包与解包CPacket 类的设计目的是处理网络传输中的数据包。它提供了封装(CPacket(WORD nCmd, const BYTE* pData, size_t nSize))和解包(CPacket(const BYTE* pData, size_t& nSize))的功能,确保数据包在传输中能够正确构建和解析。
  • 数据校验:通过校验和(sSum)确保数据包的完整性,如果校验失败,解包过程将中止。
  • 数据安全性:类中所有动态数据分配和拷贝操作都通过 std::string 进行管理,避免了手动内存管理的复杂性。

总之,CPacket 类是一个面向网络通信的数据包管理工具,它通过简单的接口和严谨的数据结构,保证了数据包的可靠传输和解析。

class CPacket
{
public:
	CPacket() :sHead(0), nLength(0), sCmd(0), sSum(0) {}
	CPacket(WORD nCmd, const BYTE* pData, size_t nSize) {
		sHead = 0xFEFF;
		nLength = nSize + 4;
		sCmd = nCmd;
		if (nSize > 0) {
			strData.resize(nSize);
			memcpy((void*)strData.c_str(), pData, nSize);
		}
		else {
			strData.clear();
		}
		sSum = 0;
		for (size_t j = 0; j < strData.size(); j++)
		{
			sSum += BYTE(strData[j]) & 0xFF;
		}
	}
	CPacket(const CPacket& pack) {
		sHead = pack.sHead;
		nLength = pack.nLength;
		sCmd = pack.sCmd;
		strData = pack.strData;
		sSum = pack.sSum;
	}
	CPacket(const BYTE* pData, size_t& nSize) {
		size_t i = 0;
		for (; i < nSize; i++) {
			if (*(WORD*)(pData + i) == 0xFEFF) {
				sHead = *(WORD*)(pData + i);
				i += 2;
				break;
			}
		}
		if (i + 4 + 2 + 2 > nSize) {//包数据可能不全,或者包头未能全部接收到
			nSize = 0;
			return;
		}
		nLength = *(DWORD*)(pData + i); i += 4;
		if (nLength + i > nSize) {//包未完全接收到,就返回,解析失败
			nSize = 0;
			return;
		}
		sCmd = *(WORD*)(pData + i); i += 2;
		if (nLength > 4) {
			strData.resize(nLength - 2 - 2);
			memcpy((void*)strData.c_str(), pData + i, nLength - 4);
			i += nLength - 4;
		}
		sSum = *(WORD*)(pData + i); i += 2;
		WORD sum = 0;
		for (size_t j = 0; j < strData.size(); j++)
		{
			sum += BYTE(strData[j]) & 0xFF;
		}
		if (sum == sSum) {
			nSize = i;//head2 length4 data...
			return;
		}
		nSize = 0;
	}
	~CPacket() {}
	CPacket& operator=(const CPacket& pack) {
		if (this != &pack) {
			sHead = pack.sHead;
			nLength = pack.nLength;
			sCmd = pack.sCmd;
			strData = pack.strData;
			sSum = pack.sSum;
		}
		return *this;
	}
	int Size() {//包数据的大小
		return nLength + 6;
	}
	const char* Data() {
		strOut.resize(nLength + 6);
		BYTE* pData = (BYTE*)strOut.c_str();
		*(WORD*)pData = sHead; pData += 2;
		*(DWORD*)(pData) = nLength; pData += 4;
		*(WORD*)pData = sCmd; pData += 2;
		memcpy(pData, strData.c_str(), strData.size()); pData += strData.size();
		*(WORD*)pData = sSum;
		return strOut.c_str();
	}

public:
	WORD sHead;//固定位 0xFEFF
	DWORD nLength;//包长度(从控制命令开始,到和校验结束)
	WORD sCmd;//控制命令
	std::string strData;//包数据
	WORD sSum;//和校验
	std::string strOut;//整个包的数据
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值