当前位置: 首页 > news >正文

二进制的协议的测试程序

一、引子

由于要调试二进制私有协议,不想用C++重头到尾写,用C++写工程量有点大,因此想找一个比较简单的工具,postman无法实现,外界的几乎找不到合适的工具,只能考虑手写一个。
前面写了一个python通过tcp协议发送二进制数据,那个是第一个版本,虽然也能做事,只是每次都要来一遍,太麻烦。
手写最快的觉得还是python,主要是熟。
不过真的开写时发现也是各种坑,要是调试一两个也就罢了,要调试很多,每个都是重头写,也能写吐。二、抽象出对请求类,接收类的处理考虑一种方案,包头,公共包头这些通信最好一次就好了,各种包的通信其实也可以封装抽象出来。实际上各包之间唯一的区别就是各个协议的发送类和接收类不一样,
这点无法共用,其它关于打包成二进制数据,由二进制数据解析成类对象,借助python强大的功能,可以直接用buffer(),unpack()全部搞定,当然,各类的成员
变量是多大是少不了得自己先定义下来了

理出来后最重要的是需要把类结构首先要转成标识这个类实际有多大的字符串集,

@staticmethod
def generate_buffer_format(fields):format_str = '<'for field_name, field_type in fields:if issubclass(field_type, ctypes.Array) and issubclass(field_type._type_, ctypes.c_char):array_length = field_type._length_format_str += f'{array_length}s'else:format_str += field_type._type_return format_str

如上代码实现了各种类最终会用类似'<BBI'等字符串表示出来,然后通过

struct.pack将其解析成二进制的buf

转成buf和由buf转换赋值给类实例中各成员变量,代码如下:

    def buffer(self) -> bytes:"""生成一个表达类实例中各成员变量大小的格式串,然后获取类实例对应每个成员的值列表,最后有了格式串,有了成员值列表,将之组装成二进制buf"""format_str = self.generate_buffer_format(self._fields_)values = self.get_fields_values(self._fields_)return struct.pack(format_str, *values)
    def unpack(self, bin_data):"""生成一个表达类实例中各成员变量大小的格式串,然后根据这样的格式串将二进制buf生成一组数值data,然后将这一组数值按顺序赋给类实例中各成员变量"""format_str = self.generate_buffer_format(self._fields_)data = struct.unpack(format_str, bin_data)for field, value in zip(self._fields_, data):setattr(self, field[0], value)

转码过成完后就是通信了,通信最主要的是不要管转码的过程,只负责数据发送和接收,然后调用各种类,由它们完成转码的过程:

如下所示:


def communication(command_id, ReqClass: Type[StructWithBuffer], RespClass: Type[StructWithBuffer]):"""二进制私有协议的通信过程,传入协议号,该协议号对应的请求类和响应类,完成请求和响应的通信过程"""client_head = ClientHead()client_pub_head = ClientPubHead()client_pub_head.iType = command_idreq_obj = ReqClass()client_head.iLen = len(client_pub_head.buffer()) + len(req_obj.buffer())final_data = client_head.buffer() + client_pub_head.buffer() + req_obj.buffer()# 建立 TCP 连接并发送数据with (socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s):s.connect((TCP_IP, TCP_PORT))s.sendall(final_data)recv_data = s.recv(ctypes.sizeof(ClientHead))recv_head = ClientHead()recv_head.unpack(recv_data)# 输出解析后的数据logging.info("recv_iLen:{}".format(recv_head.iLen))# 解析第二个包的数据并写入到 ClientPubHead 类的成员变量中recv_data = s.recv(recv_head.iLen)recv_pub_head = ClientPubHead()recv_pub_head.unpack(recv_data[:ctypes.sizeof(ClientPubHead)])logging.info("recv_iType:{}".format(recv_pub_head.iType))body_len = recv_head.iLen - ctypes.sizeof(ClientPubHead)if body_len <= 8:body_data = recv_data[ctypes.sizeof(ClientPubHead):]logging.info("recv_data_len:{},recv_data:{}".format(body_len, body_data))else:body_data = recv_data[ctypes.sizeof(ClientPubHead):]count = body_len / ctypes.sizeof(RespClass)logging.info(f"recv_body_len:{body_len}, body_count:{count}")for i in range(int(count)):resp_size = ctypes.sizeof(RespClass)data = body_data[i*resp_size: (i+1)*resp_size]info = RespClass()info.unpack(data)logging.info(f"{info}")logging.info("communication end.")

如此,就实现了一个很单纯的发送,接收,然后调用类名将之实例化,由各自的类实例完成转码。

测试代码相当简单:

if __name__ == '__main__':from binary_req_base import communicationimport logginglogging.basicConfig(format='%(asctime)s:%(module)s[%(lineno)d] %(message)s',level=logging.DEBUG)communication(3011, ReqActiveStock, RespActiveStock)

三、更高层面的抽象:

这个是一个半成品,即,只需定义各个类,即可直接完成收发的过程了,更强大的是写一个工具,然后只需在配置文件中定义各类的变量的大小即可。

另外,如果接收类是一个复杂的,外层先是一层,然后内存再有若干层,明显这个框架就不合适。需要对通信函数做重载,把这复杂的包含关系抽象出来。

相关文章:

二进制的协议的测试程序

一、引子 由于要调试二进制私有协议&#xff0c;不想用C重头到尾写&#xff0c;用C写工程量有点大&#xff0c;因此想找一个比较简单的工具&#xff0c;postman无法实现&#xff0c;外界的几乎找不到合适的工具&#xff0c;只能考虑手写一个。 前面写了一个python通过tcp协议发…...

多线程事务

一、业务场景 我们在工作中经常会到往数据库里插入大量数据的工作&#xff0c;但是既需要保证数据的一致性&#xff0c;又要保证程序执行的效率。因此需要在多线程中使用事务&#xff0c;这样既可以保证数据的一致性&#xff0c;又能保证程序的执行效率。但是spring自带的Trans…...

春秋云境CVE-2020-26048

简介 CuppaCMS是一套内容管理系统&#xff08;CMS&#xff09;。 CuppaCMS 2019-11-12之前版本存在安全漏洞&#xff0c;攻击者可利用该漏洞在图像扩展内上传恶意文件&#xff0c;通过使用文件管理器提供的重命名函数的自定义请求&#xff0c;可以将图像扩展修改为PHP&#xf…...

MySQL 带游标的存储过程(实验报告)

一、实验名称&#xff1a; 带游标的存储过程 二、实验日期&#xff1a; 2024 年 5月 25 日 三、实验目的&#xff1a; 掌握MySQL带游标的存储过程的创建及调用&#xff1b; 四、实验用的仪器和材料&#xff1a; 硬件&#xff1a;PC电脑一台&#xff1b; 配置&#xff1…...

结构体(位段)内存分配

结构体由多个数据类型的成员组成。那编译器分配的内存是不是所有成员的字节数总和呢&#xff1f; 首先&#xff0c;stu的内存大小并不为29个字节&#xff0c;即证明结构体内存不是所有成员的字节数和。   其次&#xff0c;stu成员中sex的内存位置不在21&#xff0c;即可推测…...

基于SSH的母婴用品销售管理系统带万字文档

文章目录 母婴商城系统一、项目演示二、项目介绍三、系统部分功能截图四、万字论文参考五、部分代码展示六、底部获取项目源码和万字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 母婴商城系统 一、项目演示 母婴商城系统 二、项目介绍 基于SSH的母婴商城系统 系统…...

说些什么好呢

大一&#xff1a;提前学C和C。学完语法去洛谷或者Acwing二选一&#xff0c;刷300道左右题目。主要培养编程思维&#xff0c;让自己的逻辑能够通过代码实现出来。 现在对算法有点感兴趣但是没有天赋&#xff0c;打不了acm&#xff0c;为就业做准备咯。 大二(算法竞赛)&#xff1…...

1301-习题1-1高等数学

1. 求下列函数的自然定义域 自然定义域就是使函数有意义的定义域。 常见自然定义域&#xff1a; 开根号 x \sqrt x x ​&#xff1a; x ≥ 0 x \ge 0 x≥0自变量为分式的分母 1 x \frac{1}{x} x1​&#xff1a; x ≠ 0 x \ne 0 x0三角函数 tan ⁡ x cot ⁡ x \tan x \cot x …...

C语言之指针进阶(3),函数指针

目录 前言&#xff1a; 一、函数指针变量的概念 二、函数指针变量的创建 三、函数指针变量的使用 四、两段特殊代码的理解 五、typedef 六、函数指针数组 总结&#xff1a; 前言&#xff1a; 本文主要讲述C语言指针中的函数指针&#xff0c;包括函数指针变量的概念、创建…...

RabbitMQ安装及配套Laravel使用

MQ MQ 全称 Message Queue(消息队列),是在消息的传输过程中保存消息的容器。多用于系统之间的异步通信。 为什么需要mq: 解耦:MQ能够使各个系统或组件之间解耦,降低它们之间的耦合度,提高系统的灵活性和可维护性异步处理:通过MQ可以实现异步处理,提高系统响应速度和吞…...

java在类的定义中创建自己的对象?

当在main方法中新建自身所在类的对象&#xff0c;并调用main方法时&#xff0c;会不断循环调用main方法&#xff0c;直到栈溢出 package com.keywordStudy;public class mainTest {static int value 33;public static void main(String[] args) throws Exception{String[] sn…...

掌握C++回调:按值捕获、按引用捕获与弱引用

文章目录 一、按引用捕获和按值捕获1.1 原理1.2 案例 二、弱引用2.1 原理2.2 案例一2.3 案例二&#xff1a;使用base库的弱引用 三、总结 在C回调中&#xff0c;当使用Lambda表达式捕获外部变量时&#xff0c;有两种捕获方式&#xff1a;按值捕获和按引用捕获。 一、按引用捕获…...

抖音运营_如何做出优质的短视频

目录 一 短视频内容的构成 1 图像 2 字幕 3 声音 4 特效 5 描述 6 评论 二 短视频的热门类型 1 颜值圈粉类 2 知识教学类 3 幽默搞笑类 4 商品展示类 5 才艺技能类 6 评论解说类 三 热门短视频的特征 1 产生共鸣 2 正能量 3 紧跟热点话题 4 富有创意 四 短视…...

Day21:Leetcode513.找树左下角的值 +112. 路径总和 113.路径总和ii + 106.从中序与后序遍历序列构造二叉树

LeetCode&#xff1a;513.找树左下角的值 解决方案&#xff1a; 1.思路 在遍历一个节点时&#xff0c;需要先把它的非空右子节点放入队列&#xff0c;然后再把它的非空左子节点放入队列&#xff0c;这样才能保证从右到左遍历每一层的节点。广度优先搜索所遍历的最后一个节点…...

Java数据结构和算法(B树)

前言 B树又叫平衡的多路搜索树&#xff1b;平衡的意思是又满足平衡二叉树的一些性质&#xff0c;左树大于右树&#xff1b; 多路意思是&#xff0c;可以多个结点&#xff0c;不再是像二叉树只有两个结点&#xff1b; 实现原理 B树是一种自平衡的搜索树&#xff0c;通常用于实…...

成为程序员后我都明白了什么?从入行到弃坑?

作为一个入行近10年的php程序员&#xff0c;真心感觉一切都才刚开始&#xff0c;对计算机&#xff0c;编程语言的理解也好&#xff0c;程序员中年危机也罢&#xff0c;之前都是听别人说的&#xff0c;真的自己到了这个水平&#xff0c;这个年龄才深刻体会到这其中的种种。 我一…...

python --创建固定字符串长度,先进先出

a 123def concatenate_within_limit(b, new_string):# 计算新字符串与a的长度之和a btotal_length len(a) len(new_string)# 如果长度超过1024&#xff0c;从前面删除足够的字符if total_length > 5:diff total_length - 5a a[diff:] new_string # 删除前diff个字符…...

容器化部署

目录 docker容器化部署 怎样使用Docker Compose或Kubernetes等容器编排工具来管理和扩展联邦学习系统 使用Docker Compose...

国产数据库TiDB的常用方法

TiDB的常用方法主要涉及安装配置、数据操作、性能调优以及监控和维护等方面。以下是对这些常用方法的归纳和介绍&#xff1a; 1. 安装与配置 安装TiDB&#xff1a;根据官方文档的指引&#xff0c;用户可以按照步骤进行TiDB的安装。配置TiDB&#xff1a;安装完成后&#xff0c…...

基于DdddOcr通用验证码离线本地识别SDK搭建个人云打码接口Api

前言 最近介绍了一款免费的验证码识别网站,识别效率太低,考虑到ddddocr是开源的,决定搭建搭建一个,发现原作者sml2h3已经推出好久了,但是网上没有宝塔安装的教程,于是本次通过宝塔搭建属于自己的带带弟弟OCR通用验证码离线本地识别 原项目地址:https://github.com/sml2…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...