5.后台运行设置和包设计与实现

程序的入口点(想让其后台默认.exe进程运行)

也可以不通过vs设置也可以通过定义预处理设置

第三种就是没有窗口的

变成后台运行的了

处理client传来的数据包

第一步:咱们怎么设计一种包呢?

FEFF在网络环境里面出现的概率低所以就采用这个

自己数据包截断了,运行在公网时候有很多嗅探包,其他应用的误发

c 复制代码
class CPacket
{

public:
	WORD sHead; //FEFF
	DWORD nLength; //包长度(从控制命令开始到和校验结束)
	WORD sCmd; //控制命令,为了对齐习惯用WORD
	std::string strData; //要发的包数据
	WORD sSum;//和校验

public:
	CPacket() :sHead(0), nLength(0), sCmd(0), sSum(0) {}//无参构造函数
    
    CPacket(const CPacket& pack) {
		sHead = pack.sHead;
		nLength = pack.nLength;
		sCmd = pack.sCmd;
		strData = pack.strData;
		sSum = pack.sSum;
	}

	CPacket(WORD nCmd, const BYTE* pData, size_t nSize) { //常量指针,指向的内容不能改变
		sHead = 0xFEFF; //头
		nLength = nSize + 2 + 2; //数据的长度加上命令长度加上校验的长度
		sCmd = nCmd; //命令
		if (nSize > 0) { //有数据
			strData.resize(nSize); //给包data容器重新设置长度
			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 BYTE* pData, size_t& nSize) { //一开始传入的这个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; //用掉了0个字节
			return;
		}
        
		nLength = *(DWORD*)(pData + i); i += 4;
        
		if (nLength + i > nSize) { //包未完全接收到,就返回,解析失败,半个包
			nSize = 0;//用掉了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); //将pData + i起始地址的nLength - 4个连续的字节复制到包的data区
			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;//nLength + 2 + 4;//head length 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;
	}
};

注意nSize是地址传过来的,所以nSize全局跟随,为什么这里不用Length呢?因为前面可能有废数据,所以用nSize(程序里面的i)

接下来继续写上一章没有完成的DealCmd了

c 复制代码
	int DealCommand() { //无限循环
		if (m_client == -1) return -1; //断开连接了
		//char buffer[1024] = "";
		char* buffer = new char[4096]; //缓冲区
		memset(buffer, 0, 4096); //缓冲区置0
		size_t index = 0; //一开始从0开始的
		while (true) {
			size_t len = recv(m_client, buffer + index, 4096 - index, 0); //index是用掉的
			if (len <= 0) {
				return -1;
			}
			index += len; //可能收到2000个字节的包
			len = index;
			m_packet = CPacket((BYTE*)buffer, index); //将缓冲区包化
			//这个地方出来的index就是处理包获得一段有效包用掉的大小
			if (len > 0) { //其实这段是废话,能到这里len已经大于0了
				memmove(buffer, buffer + len, 4096 - len);//从buffer + len复制4096-len个字节到buffer,将下一个包数据往前挪
				index -= len; //可能只用1000个
				return m_packet.sCmd;
			}
		}
		return -1;
	}

index表示整个缓冲区当前剩余的字节(可能用掉了一个包,可能用掉了多个包)

len在包处理以前(CPacket)表示包的长度,在包处理以后(CPacket)表示这个完整的包用掉了多少字节

本质就是客户端丢一坨数据(一般不超过4KB),自己想办法解析

相关推荐
赋创小助手18 分钟前
融合与跃迁:NVIDIA、Groq 与下一代 AI 推理架构的博弈与机遇
服务器·人工智能·深度学习·神经网络·语言模型·自然语言处理·架构
李艺为24 分钟前
根据apk包名动态修改Android品牌与型号
android·开发语言
电商API&Tina1 小时前
跨境电商 API 对接指南:亚马逊 + 速卖通接口调用全流程
大数据·服务器·数据库·python·算法·json·图搜索算法
IT19951 小时前
Qt笔记-使用SSH2进行远程连接linux服务器并上传文件
linux·服务器·笔记
黄河滴滴1 小时前
java系统变卡变慢的原因是什么?从oom的角度分析
java·开发语言
老华带你飞1 小时前
农产品销售管理|基于java + vue农产品销售管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
superman超哥1 小时前
Rust Workspace 多项目管理:单体仓库的优雅组织
开发语言·rust·多项目管理·rust workspace·单体仓库
北京盟通科技官方账号1 小时前
工业通讯底层对齐:EtherNet/IP Class 1 连接中的 32-bit Header 与内存映射逻辑
服务器·网络·网络协议·自动化·制造
kylezhao20192 小时前
C#通过HSLCommunication库操作PLC用法
开发语言·c#
lengjingzju2 小时前
一网打尽Linux IPC(三):System V IPC
linux·服务器·c语言