二进制的协议的测试程序
一、引子
由于要调试二进制私有协议,不想用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)
三、更高层面的抽象:
这个是一个半成品,即,只需定义各个类,即可直接完成收发的过程了,更强大的是写一个工具,然后只需在配置文件中定义各类的变量的大小即可。
另外,如果接收类是一个复杂的,外层先是一层,然后内存再有若干层,明显这个框架就不合适。需要对通信函数做重载,把这复杂的包含关系抽象出来。
相关文章:
二进制的协议的测试程序
一、引子 由于要调试二进制私有协议,不想用C重头到尾写,用C写工程量有点大,因此想找一个比较简单的工具,postman无法实现,外界的几乎找不到合适的工具,只能考虑手写一个。 前面写了一个python通过tcp协议发…...

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

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

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

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

基于SSH的母婴用品销售管理系统带万字文档
文章目录 母婴商城系统一、项目演示二、项目介绍三、系统部分功能截图四、万字论文参考五、部分代码展示六、底部获取项目源码和万字论文参考(9.9¥带走) 母婴商城系统 一、项目演示 母婴商城系统 二、项目介绍 基于SSH的母婴商城系统 系统…...
说些什么好呢
大一:提前学C和C。学完语法去洛谷或者Acwing二选一,刷300道左右题目。主要培养编程思维,让自己的逻辑能够通过代码实现出来。 现在对算法有点感兴趣但是没有天赋,打不了acm,为就业做准备咯。 大二(算法竞赛)࿱…...

1301-习题1-1高等数学
1. 求下列函数的自然定义域 自然定义域就是使函数有意义的定义域。 常见自然定义域: 开根号 x \sqrt x x : x ≥ 0 x \ge 0 x≥0自变量为分式的分母 1 x \frac{1}{x} x1: x ≠ 0 x \ne 0 x0三角函数 tan x cot x \tan x \cot x …...

C语言之指针进阶(3),函数指针
目录 前言: 一、函数指针变量的概念 二、函数指针变量的创建 三、函数指针变量的使用 四、两段特殊代码的理解 五、typedef 六、函数指针数组 总结: 前言: 本文主要讲述C语言指针中的函数指针,包括函数指针变量的概念、创建…...

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

java在类的定义中创建自己的对象?
当在main方法中新建自身所在类的对象,并调用main方法时,会不断循环调用main方法,直到栈溢出 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 案例二:使用base库的弱引用 三、总结 在C回调中,当使用Lambda表达式捕获外部变量时,有两种捕获方式:按值捕获和按引用捕获。 一、按引用捕获…...

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

Day21:Leetcode513.找树左下角的值 +112. 路径总和 113.路径总和ii + 106.从中序与后序遍历序列构造二叉树
LeetCode:513.找树左下角的值 解决方案: 1.思路 在遍历一个节点时,需要先把它的非空右子节点放入队列,然后再把它的非空左子节点放入队列,这样才能保证从右到左遍历每一层的节点。广度优先搜索所遍历的最后一个节点…...
Java数据结构和算法(B树)
前言 B树又叫平衡的多路搜索树;平衡的意思是又满足平衡二叉树的一些性质,左树大于右树; 多路意思是,可以多个结点,不再是像二叉树只有两个结点; 实现原理 B树是一种自平衡的搜索树,通常用于实…...
成为程序员后我都明白了什么?从入行到弃坑?
作为一个入行近10年的php程序员,真心感觉一切都才刚开始,对计算机,编程语言的理解也好,程序员中年危机也罢,之前都是听别人说的,真的自己到了这个水平,这个年龄才深刻体会到这其中的种种。 我一…...
python --创建固定字符串长度,先进先出
a 123def concatenate_within_limit(b, new_string):# 计算新字符串与a的长度之和a btotal_length len(a) len(new_string)# 如果长度超过1024,从前面删除足够的字符if total_length > 5:diff total_length - 5a a[diff:] new_string # 删除前diff个字符…...
容器化部署
目录 docker容器化部署 怎样使用Docker Compose或Kubernetes等容器编排工具来管理和扩展联邦学习系统 使用Docker Compose...
国产数据库TiDB的常用方法
TiDB的常用方法主要涉及安装配置、数据操作、性能调优以及监控和维护等方面。以下是对这些常用方法的归纳和介绍: 1. 安装与配置 安装TiDB:根据官方文档的指引,用户可以按照步骤进行TiDB的安装。配置TiDB:安装完成后,…...

基于DdddOcr通用验证码离线本地识别SDK搭建个人云打码接口Api
前言 最近介绍了一款免费的验证码识别网站,识别效率太低,考虑到ddddocr是开源的,决定搭建搭建一个,发现原作者sml2h3已经推出好久了,但是网上没有宝塔安装的教程,于是本次通过宝塔搭建属于自己的带带弟弟OCR通用验证码离线本地识别 原项目地址:https://github.com/sml2…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

WinUI3开发_使用mica效果
简介 Mica(云母)是Windows10/11上的一种现代化效果,是Windows10/11上所使用的Fluent Design(设计语言)里的一个效果,Windows10/11上所使用的Fluent Design皆旨在于打造一个人类、通用和真正感觉与 Windows 一样的设计。 WinUI3就是Windows10/11上的一个…...

SeaweedFS S3 Spring Boot Starter
SeaweedFS S3 Spring Boot Starter 源码特性环境要求快速开始1. 添加依赖2. 配置文件3. 使用方式方式一:注入服务类方式二:使用工具类 API 文档SeaweedFsS3Service 主要方法SeaweedFsS3Util 工具类方法 配置参数运行测试构建项目注意事项集成应用更多项目…...

MySQL技术内幕1:内容介绍+MySQL编译使用介绍
文章目录 1.整体内容介绍2.下载编译流程2.1 安装编译工具和依赖库2.2 下载编译 3.配置MySQL3.1 数据库初始化3.2 编辑配置文件3.3 启动停止MySQL3.4 登录并修改密码 1.整体内容介绍 MySQL技术系列文章将从MySQL下载编译,使用到MySQL各组件使用原理源码分析…...