tunm二进制协议在python上的实现

tunm是一种对标JSON的二进制协议, 支持JSON的所有类型的动态组合

支持的数据类型

基本支持的类型 “u8”, “i8”, “u16”, “i16”, “u32”, “i32”, “u64”, “i64”, “varint”, “float”, “string”, “raw”, “array”, “map”

为什么我们需要二进制协议

下图是文本格式JSON与tunm的对比

类型 可读 可编辑 编码速度 解码速度 数据大小 预定义 JSON ✓ ✓ 慢 慢 大 否 tunm x x 快 快 小 否 protobuf x x 快 快 小 是

在高性能的场景下, 或者需要流量传输比较敏感的地方, 通常会选择二进制来代替文本协议来做为通讯的, 如RPC, REST, 游戏等情况。
相对于google protobuf, 它需要比较完善的预定义过程, 就比如客户端版本1, 服务端版本2, 就有比较大的可能造成不兼容, 对需求经常变化的就会比较难与同步。
tunm相对于JSON, 若第一版是

{
    "name": "tunm", "version": 1
}

此时第二版需要加入用户的id, 就可以很方便的变成

{
    "name": "tunm", "version": 2, "id": 1
}

而对客户端1来说, 只是多一个id的字段, 不会有任何的破坏, 做到版本升级而无影响

协议的二进制格式

数据协议分为三部分(协议名称, 字符串索引区, 数据区(默认为数组))
如数据协议名为cmd_test_op, 数据为[“tunm_proto”, {“name”: “tunm_proto”, “tunm_proto”: 1}]

协议的实现(小端对齐)

ByteBuffer具有组装字节流的功能, 比如写入字符串, 写入int, 还有里面存储字符串索引区

class ByteBuffer(object):
    def __init__(self):
        # 字节缓冲区
        self.buffer = bytearray([00]*1024)
        # 写入的位置索引号
        self.wpos = 0
        # 读出的位置索引号
        self.rpos = 0
        # 大小端格式
        self.endianness = "little"
        # 索引的数组及快速查询的字符串索引号
        self.str_arr = []
        self.str_map = {}
@enum.unique
class TP_DATA_TYPE(IntEnum):
    TYPE_NIL = 0,
    TYPE_BOOL = 1,
    TYPE_U8 = 2,
    TYPE_I8 = 3,
    TYPE_U16 = 4,
    TYPE_I16 = 5,
    TYPE_U32 = 6,
    TYPE_I32 = 7,
    TYPE_U64 = 8,
    TYPE_I64 = 9,
    TYPE_VARINT = 10,
    TYPE_FLOAT = 11,
    TYPE_DOUBLE = 12,
    TYPE_STR = 13,
    TYPE_STR_IDX = 14,
    TYPE_RAW = 15,
    TYPE_ARR = 16,
    TYPE_MAP = 17,
@staticmethod
def encode_varint(buffer: ByteBuffer, value):
    '''
    如果原数值是正数则将原数值变成value*2
    如果原数值是负数则将原数值变成-(value + 1) * 2 + 1
    相当于0->0, -1->1, 1->2,-2->3,2->4来做处理
    因为小数值是常用的, 所以保证小数值及负数的小数值尽可能的占少位
    '''
    if type(value) == bool:
        value = 1 if value else 0
    real = value * 2
    if value < 0:
        real = -(value + 1) * 2 + 1

    for _i in range(12):
        # 每个字节的最高位来表示有没有下一位, 若最高位为0, 则已完毕
        b = real & 0x7F
        real >>= 7
        if real > 0:
            buffer.write_u8(b | 0x80)
        else:
            buffer.write_u8(b)
            break
@staticmethod
def encode_str_idx(buffer: ByteBuffer, value):
    '''
    写入字符串索引值, 在数值区里的所有字符串默认会被写成索引值
    如果重复的字符串则会返回相同的索引值(varint)
    '''
    idx = buffer.add_str(value)
    TPPacker.encode_type(buffer, TP_DATA_TYPE.TYPE_STR_IDX)
    TPPacker.encode_varint(buffer, idx)
@staticmethod
def encode_field(buffer: ByteBuffer, value, pattern=None):
    '''
    先写入类型的值(u8), 则根据类型写入类型对应的的数据
    '''
    if not pattern:
        pattern = TPPacker.get_type_by_ref(value)
    if pattern == TP_DATA_TYPE.TYPE_NIL:
        return None
    elif pattern == TP_DATA_TYPE.TYPE_BOOL:
        TPPacker.encode_type(buffer, pattern)
        TPPacker.encode_bool(buffer, value)
    elif pattern >= TP_DATA_TYPE.TYPE_U8 and pattern = TP_DATA_TYPE.TYPE_U16 and pattern
@staticmethod
def encode_proto(buffer: ByteBuffer, name, infos):
    '''
    写入协议名称, 然后写入字符串索引区(即字符串数组), 然后再写入协议的详细数据
    '''
    sub_buffer = ByteBuffer()
    TPPacker.encode_field(sub_buffer, infos)

    TPPacker.encode_str_raw(buffer, name, TP_DATA_TYPE.TYPE_STR)
    TPPacker.encode_varint(buffer, len(sub_buffer.str_arr))
    for val in sub_buffer.str_arr:
        TPPacker.encode_str_raw(buffer, val, TP_DATA_TYPE.TYPE_STR)

    buffer.write_bytes(sub_buffer.all_bytes())

Original: https://www.cnblogs.com/luojiawaf/p/16411608.html
Author: 行稳致远up
Title: tunm二进制协议在python上的实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/499217/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【Python刷题篇】Python从0到入门2|列表复习、循环语句、条件语句

    Python从0到入门2目录 前言 Q1:列表-投递简历 Q2:排序与反转 Q3:循环-字符列表的长度 Q4:循环-程序员节 Q5:条件-找到HR Q6:条件-判断列表是否为空 总…

    Python 2023年8月2日
    073
  • 计算时间相加–时间戳方式

    仅作为记录,核心代码 int timestamp = (hours + t.hours) * 60 * 60 + (minutes+t.minutes) * 60 + (secon…

    Python 2023年6月11日
    075
  • 初探富文本之富文本概述

    富文本编辑器通常指的是可以对文字、图片等进行编辑的产品,具有所见即所得的能力。对于 Input、 Textarea之类标签,他们是支持内容编辑的,但并不支持带格式的文本或者是图片的…

    Python 2023年10月14日
    061
  • manim svg的bug

    在网上下载了一个雪人svg,发现在manim中不能正常显示圆的部分(已经是路径了)。好在点击圆后可以使用图形工具创造出一模一样的圆来(移动到圆的两个对角即可) Original: …

    Python 2023年6月12日
    063
  • Python学习:property装饰器

    装饰器:装饰器是在不修改被装饰对象源代码以及调用方式的前提下为被装饰对象添加新功能的可调用对象 property是一个装饰器,是用来绑定给对象的方法伪造成一个数据属性 装饰器pro…

    Python 2023年6月9日
    092
  • 4.请求与响应

    目录 1 请求 2 响应 1 请求 http的请求一般分下面几个部分 起始行,起始行中主要有下面几个信息 请求方法(get,post等) 请求的哪一个路由 此次http请求的协议号…

    Python 2023年8月5日
    062
  • 【毕业设计】基于大数据的抖音短视频数据分析与可视化 – python 大数据 可视化

    文章目录 0 前言 1 课题背景 2 数据清洗 3 数据可视化 * 地区-用户 观看时间 分界线 每周观看 观看路径 发布地点 视频时长 整体点赞、完播 4 进阶分析 * 相关性分…

    Python 2023年7月31日
    062
  • matplotlib教程05—操作图像

    文章目录 欢迎关注公众号【Python开发实战】,免费领取Python学习电子书! 工具-matplotlib * 保存图像 读取图像 生成图像 欢迎关注公众号【Python开发实…

    Python 2023年9月1日
    045
  • 【翻译】Raft 共识算法:集群成员变更

    转载请注明出处:https://www.cnblogs.com/morningli/p/16770129.html 之前都在集群配置是固定的(参与共识算法的server集合)假设下…

    Python 2023年10月18日
    041
  • Python中的True和False详解

    Python中的 True和 False总是让人困惑,一不小心就会用错,本文总结了三个易错点,分别是逻辑取反、if条件式和pandas.DataFrame.loc切片中的条件式。 …

    Python 2023年8月6日
    038
  • (Scrapy框架)爬虫2021年CSDN全站综合热榜标题热词 | 爬虫案例

    目录 前言 环境部署 实现过程 创建项目 定义Item实体 关键词提取工具 爬虫构造 中间件代码构造 制作自定义pipeline settings配置 执行主程序 执行结果 总结 …

    Python 2023年10月2日
    052
  • 《Python程序设计与算法基础教程(第二版)》江红 余青松 课后选择题 课后填空题答案

    一、选择题 Python语言属于 C A.机器语言 B.汇编语言 C.高级语言 D.以上都不是 在下列选项中,不属于Python特点的是 B C.可移植性 D.免费和开源 A.面向…

    Python 2023年8月2日
    064
  • 最全ubuntu-Anaconda换源问题/恢复默认源,一篇就够

    万恶的换源操作,acaconda突然下载变慢了,以为是源的问题,一不小心就把源换了,后来,排查发现是网速没跟上,而各种换源方式都尝试了一波,发现源依旧报各种错误,如: 总之,优先建…

    Python 2023年9月7日
    080
  • jupyter notebook 中文乱码问题解决——MAC版本

    一、检测图形是否支持中文 二、解决方案 临时方案:每次画图时都带着这几段代码(….挺麻烦) 永久方案:安装simhei.tff 字体 1、下载字体下载地址:https:…

    Python 2023年9月1日
    068
  • 云服务多语言 SDK

    云服务一般提供了一个文档来描述提供的 OpenAPI,然会每个用户根据文档自己实现签名、调用等功能的封装,这部分会出现各种各样的问题,因此用户更希望平台直接提供一个 SDK。 da…

    Python 2023年10月21日
    054
  • 用ssh无密码登录远程linux

    登录linux常用的方式是:用户名+密码,多次输入密码非常不方便,所以推荐使用密钥登录,安全又方便,下面我说下怎么使用密钥登录。 *生成密钥 使用密钥登录首先需要本地有ssh密钥 …

    Python 2023年6月3日
    079
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球