XTCP 一个便捷的TCP消息包拼装和解析框架

简介: XTCP 一个便捷的TCP消息包拼装和解析框架

XTCP


项目地址: github.com/xuexiangjys…, 喜欢的欢迎star收藏!~~


一个便捷的TCP消息包拼装和解析框架


特征


  • 简单通过@Protocol@ProtocolField的配置,即可让实体对象拥有自动转化为TCP传输的byte数据和自动byte数据解析。


  • 支持byte、short、int、long、byte[]、short[]、int[]、long[]、String等常用基础类型,支持类型的拓展。


  • 支持无符号数和有符号数两种。


  • 支持BCD编码格式【时间、int、float、double等】。


  • 支持大端和小端两种存储方式,支持设置全局默认存储方式和局部存储方式。


  • 支持short、int、long读取长度的自定义。


  • 支持对实体字段进行排序,避免解析错乱。


  • 支持自定义协议项和协议解析器。


  • 支持对不定长数组解析【需要注意的是,在一条协议中有且只能有一个不定长的数组,否则将无法解析成功】。


  • 支持自动协议映射,自动根据读取的opcode识别出对应的协议并进行解析,并根据对应注册的协议信息判断协议是否有响应。


1、演示(请star支持)


2、如何使用


目前支持主流开发工具AndroidStudio的使用,直接配置build.gradle,增加依赖即可.


2.1 添加Gradle依赖


1.先在项目根目录的 build.gradle 的 repositories 添加:


allprojects {
     repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}


2.然后在dependencies添加:


dependencies {
  ...
  implementation 'com.github.xuexiangjys.XTCP:xtcp_runtime:1.0.7'
  annotationProcessor 'com.github.xuexiangjys.XTCP:xtcp_compiler:1.0.7'
}


3.进行moduleName注册


defaultConfig {
    ...
    javaCompileOptions {
        annotationProcessorOptions {
            arguments = [ moduleName : project.getName() ]
        }
    }
}


【注意】:如果不注册的话,默认ModuleName为app


2.2 初始化协议中心


在Application中注册协议中心和协议字段中心。


XTCP.getInstance()
        .addIProtocolCenter(AppProtocolCenter.getInstance()) //添加协议中心
        .addIProtocolFieldCenter(AppProtocolFieldCenter.getInstance(), XTCPProtocolFieldCenter.getInstance()) //添加协议字段中心
        .setDefaultStorageMode(StorageMode.BigEndian) //设置默认存储方式(默认是大端)
        .debug(true); //打开调试日志


2.3 构建通信协议实体


通过继承XProtocolItem或者实现IProtocolItem接口,通过@Protocol@ProtocolField注解进行配置。


  • @Protocol: 用于注解协议项,包括nameopcoderesCodemodedesc等属性。


  • @ProtocolField: 用于注解协议项字段,包括indexisFieldlengthmodecharset等属性。


@Protocol(name = "参数设置请求", opCode = 0x12, resCode = 0x33, desc = "注意重启下位机后生效!")
public class SettingRequest extends XProtocolItem {
    @ProtocolField(index = 0)
    private byte func1;
    @ProtocolField(index = 1)
    private short func2;
    @ProtocolField(index = 2)
    private int func3;
    @ProtocolField(index = 3)
    private long func4;
    @ProtocolField(index = 4)
    private ByteArray list1;
    @ProtocolField(index = 5)
    private ShortArray list2;
    @ProtocolField(index = 6)
    private IntArray list3;
    @ProtocolField(index = 7)
    private LongArray list4;
    @ProtocolField(index = 8)
    private StringField string1;
    @ProtocolField(index = 9)
    private LargeString string2;
    @ProtocolField(index = 10)
    private TestProtocolItem testItem;
    @ProtocolField(index = 11)
    private LoginInfo loginInfo;
    @ProtocolField(index = 12)
    private BCD<Date> time = new BCD<>(Date.class, "yy-MM-dd HH:mm:ss");
    @ProtocolField(index = 13)
    private BCD<Integer> number = new BCD<>(Integer.class, "XXX");
    @ProtocolField(index = 14)
    private BCD<Float> total = new BCD<>(Float.class, "XXXXX.XX");
    @ProtocolField(index = 15)
    private BCD<Double> money = new BCD<>(Double.class, "XXXXX.XX");
    @ProtocolField(index = 16)
    private FixedString ID = new FixedString(10);
    @ProtocolField(index = 17)
    private LoginInfoArray loginInfos;
    @ProtocolField(index = 18, unsigned = false)
    private short signedShort;
    @ProtocolField(index = 19, unsigned = false)
    private int signedInt;
    @ProtocolField(index = 20, unsigned = false)
    private long signedLong;
}


2.4 自定义协议项和协议项数组


自定义协议项


要想自定义协议项很简单,同样的,只需要继承XProtocolItem或者实现IProtocolItem接口,使用@ProtocolField注解进行配置即可。


【注意】不需要使用@Protocol进行注解。


public class LoginInfo extends XProtocolItem {
    @ProtocolField(index = 0)
    private StringField loginName;
    @ProtocolField(index = 1)
    private StringField password;
}


自定义协议项数组


自定义协议项数组类需要继承AbstractArrayItem,详细的实现案例点击查看


2.5 协议项的byte化和反byte化


凡是继承XProtocolItem或者实现IProtocolItem接口,都将有如下两个方法:


/**
 * 将协议实体转化为byte数组
 *
 * @param storageMode 存储形式
 * @return
 */
byte[] proto2byte(StorageMode storageMode);
/**
 * 将byte数组数据转化为协议实体
 *
 * @param bytes       byte数组数据
 * @param index       起始字节
 * @param tailLength  消息尾的长度[和index一起决定了数据解析的范围]
 * @param storageMode 存储形式
 * @return 是否解析成功
 */
boolean byte2proto(byte[] bytes, int index, int tailLength, StorageMode storageMode);


使用案例如下:


SettingRequest request = new SettingRequest()
        .setFunc1((byte) 0x45)
        .setFunc2((short) 12)
        .setFunc3(2345)
        .setFunc4((long) 1213131233)
        .setList1((byte) 0x23, (byte) 0x45, (byte) 0x56)
        .setList2((short) 11, (short) 22, (short) 33)
        .setList3(111, 222, 333)
        .setList4((long) 1221312, (long) 23123123)
        //长度超过255的话,就溢出了
        .setString1("我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!")
        .setString2("我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!" +
                "我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!" +
                "我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!" +
                "我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!" +
                "我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!" +
                "我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!" +
                "我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!我的名字叫薛翔!")
        .setLoginInfo(new LoginInfo("xuexiang", "123456"))
        .setTime(new Date())
        .setNumber(123)
        .setTotal(12345.67F)
        .setMoney(23456.78)
        .setID("1234567890")
        .setLoginInfos(new LoginInfo("xuexiang1", "222"),
                new LoginInfo("xuexiang23", "3333"),
                new LoginInfo("xuexiang456", "44444"))
        .setTestItem(new TestProtocolItem()
                .setFunc1((byte) 0x56)
                .setFunc2((short) 314)
                .setFunc3(6111)
                .setFunc4((long) 35536234)
                .setList1(314, 334, 34235, 67584, 45234, 6757)
                .setLoginInfo(new LoginInfo("xuexiangjys", "111111")))
        .setSignedShort((short) -678)
        .setSignedInt(-214)
        .setSignedLong(-14523L);
byte[] bytes = request.proto2byte(StorageMode.Default);
Log.e("xuexiang", ConvertUtils.bytesToHexString(bytes));
SettingRequest request1 = new SettingRequest();
request1.byte2proto(bytes, 0, 0, StorageMode.Default);
Log.e("xuexiang", request1.toString());


2.6 消息体包装与解析


实现IMessage接口,可自定义属于自己的协议消息载体。框架中默认提供了XMessageXOrderlyMessage两种消息体模版。




消息转byte的使用方法


  • 1.新建你需要使用的消息体模版。


  • 2.设置你传输的协议项。


  • 3.使用msg2Byte方法将消息转化为byte数组数据。


byte转消息的使用方法


  • 1.新建你需要转化的消息体模版。


  • 2.使用byte2Msg方法,传入byte数组数据进行转化。


MessageTest messageTest = new MessageTest()
        .setFunc1((byte) 0x45)
        .setFunc2((short) 12)
        .setFunc3(2345)
        .setFunc4((long) 1213131233)
        .setList2((short) 11, (short) 22, (short) 33)
        .setLoginInfo(new LoginInfo("xuexiang", "123456"));
XMessage message = new XMessage()
        .setIProtocolItem(messageTest);
byte[] bytes = message.msg2Byte();
Log.e("xuexiang", ConvertUtils.bytesToHexString(bytes));
XMessage message1 = new XMessage();
boolean result = message1.byte2Msg(bytes);
Log.e("xuexiang", "result:" + result +", ProtocolItem:" + message1.getProtocolItem());


2.7 自定义协议解析器


如果你对协议的解析有特殊的需求,可实现IProtocolParser接口,并通过XTCP.getInstance().setIProtocolParser来替换默认的协议解析器


【注意】谨慎替换,如果替换方法有误的话,会导致整个框架无法正常使用,建议不要替换。


3、基础内容介绍


协议项注解@Protocol


属性名 类型 默认值 备注
name String "" 协议的名称
opCode byte /(必填) 协议命令码,协议命令的唯一号
resCode byte -1 协议响应码(结果对应的命令码)
mode StorageMode StorageMode.Default 数据存储方式(大端 or 小端)
desc String "" 描述信息


协议字段注解@ProtocolField


属性名 类型 默认值 备注
index int /(必填) 字段的顺序索引
isField boolean true 是否为协议解析字段
length int -1 协议字段的长度, 不设置的话,默认自动识别
unsigned boolean true 是否是无符号数
mode StorageMode StorageMode.Default 数据存储方式(大端 or 小端)
charset String "UTF-8" 字符集(只对String有效)


基础数组数据类型


类名 对应的数组类型 数组最大长度
ByteArray byte[] 255
LargeByteArray byte[] 65535
IntArray int[] 255
ShortArray short[] 255
LongArray long[] 255
StringField String 255
LargeString String 65535


【注意】:框架支持不定长数组,如果你的数组长度不定(没有确定长度的字段),那么你有且只能有这么一个数组可以不使用以上的数组包装类。


4、混淆配置


# xtcp
-keep @com.xuexiang.xtcp.annotation.* class * {*;}
-keep class * {
    @com.xuexiang.xtcp.annotation.* <fields>;
}
-keepclassmembers class * {
    @com.xuexiang.xtcp.annotation.* <methods>;
}



目录
打赏
0
0
0
0
1
分享
相关文章
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
193 27
ViDoRAG:开源多模态文档检索框架,多智能体推理+图文理解精准解析文档
ViDoRAG 是阿里巴巴通义实验室联合中国科学技术大学和上海交通大学推出的视觉文档检索增强生成框架,基于多智能体协作和动态迭代推理,显著提升复杂视觉文档的检索和生成效率。
213 8
ViDoRAG:开源多模态文档检索框架,多智能体推理+图文理解精准解析文档
Java机器学习实战:基于DJL框架的手写数字识别全解析
在人工智能蓬勃发展的今天,Python凭借丰富的生态库(如TensorFlow、PyTorch)成为AI开发的首选语言。但Java作为企业级应用的基石,其在生产环境部署、性能优化和工程化方面的优势不容忽视。DJL(Deep Java Library)的出现完美填补了Java在深度学习领域的空白,它提供了一套统一的API,允许开发者无缝对接主流深度学习框架,将AI模型高效部署到Java生态中。本文将通过手写数字识别的完整流程,深入解析DJL框架的核心机制与应用实践。
222 3
自己动手编写tcp/ip协议栈1:tcp包解析
学习tuntap中的tun的使用方法,并使用tun接口解析了ip包和tcp包,这是实现tcp/ip协议栈的第一步。
106 15
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
TCP报文格式全解析:网络小白变高手的必读指南
本文深入解析TCP报文格式,涵盖源端口、目的端口、序号、确认序号、首部长度、标志字段、窗口大小、检验和、紧急指针及选项字段。每个字段的作用和意义详尽说明,帮助理解TCP协议如何确保可靠的数据传输,是互联网通信的基石。通过学习这些内容,读者可以更好地掌握TCP的工作原理及其在网络中的应用。
|
8月前
|
网络通信的基石:TCP/IP协议栈的层次结构解析
在现代网络通信中,TCP/IP协议栈是构建互联网的基础。它定义了数据如何在网络中传输,以及如何确保数据的完整性和可靠性。本文将深入探讨TCP/IP协议栈的层次结构,揭示每一层的功能和重要性。
377 5
深入解析:TCP与UDP的核心技术差异
在网络通信的世界里,TCP(传输控制协议)和UDP(用户数据报协议)是两种核心的传输层协议,它们在确保数据传输的可靠性、效率和实时性方面扮演着不同的角色。本文将深入探讨这两种协议的技术差异,并探讨它们在不同应用场景下的适用性。
231 4
网络通信的核心选择:TCP与UDP协议深度解析
在网络通信领域,TCP(传输控制协议)和UDP(用户数据报协议)是两种基础且截然不同的传输层协议。它们各自的特点和适用场景对于网络工程师和开发者来说至关重要。本文将深入探讨TCP和UDP的核心区别,并分析它们在实际应用中的选择依据。
216 3
|
8月前
|
深入解析:TCP四次挥手断开连接的全过程及必要性
在网络通信中,TCP(传输控制协议)以其可靠性和顺序保证而闻名。然而,TCP连接的建立和终止同样重要,它们确保了网络资源的有效管理和数据传输的完整性。本文将详细描述TCP连接的四次挥手过程,并探讨为何需要四次挥手来正确终止一个TCP连接。
233 2

热门文章

最新文章

推荐镜像

更多
  • DNS
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等

    登录插画

    登录以查看您的控制台资源

    管理云资源
    状态一览
    快捷访问