跳至主要內容

二次开发

大约 6 分钟

二次开发

本章节列举希望对sekiro框架进行二次开发的指导和相关资源

源码列表

Sekio是一个半开源项目,其核心功能在github开源,同时有一个带有高级功能的收费分支是闭源发展。你可以根据本章节的引导了解Sekiro的所有组成部分。以及考量选择商业版还是开源版本。

源码仓库列表:

客户端sdk开发

Sekiro已经为多种语言提供了sdk,这些语言包括:Frida、Java(Xposed)、Objective-c(IOS)、js(web)、python、go、c#, 如果您的需求场景并不是上诉语言,则可能需要自行完成sekiro的sdk开发,才能进行sekiro服务接入。

sekiro核心是一个socket的网络程序,他运行sekiro定义的一个私有协议结构,并且依靠包结构编码使得单一tcp隧道可以并行传输多个业务负载session,你需要了解sekiro的二进制协议才能进行对应的sdk开发。

当你开发自己的sdk的时候,建议选择上述任何一门您熟悉的语言作为参考

报文结构

SekiroProtocol

magic

长度 8 byte; 魔数,固定值sekiro01,其中 01 代表协议版本号,目前是 01 版本。

total_leng(total_length)

长度 4 byte; total_leng 的值为数据包从 type 开始直到该数据包结束占用的字节数,不包括魔数占用字节数和 total_leng 占用字节数,即 total_leng 的值为整体数据包总长度减去 12。

type

长度 1 byte; 代表该数据包的类型

- 0x00 心跳包数据包
- 0x10 客户端向服务端注册 group 数据包
- 0x11 客户端向服务端响应数据包
- 0x20 服务端调用客户端数据包

seq_id

长度 4 byte; 该数据包序列号,唯一标示该次请求;由服务端下发请求时设置,客户端在响应该次请求时设置为相同值

header_size

长度 1 byte; 代表该次数据包中有多少个消息头,当前协议要求最大值不能超过127

key_len

长度 1 byte; 该消息头 key 的内容长度,

key

长度不固定,由 key_len 的值决定,该消息头的 key,当前协议要求最长不能超过 127 个字节;

value_len

长度 1 byte; 该消息头 value 的长度

value

长度不固定,由 value_len 的值决定;该消息头的 value,当前协议要求最长不能超过 127 个字节;

data

长度不固定,由 total_leng 的值减去从 type 开始到 data 之前占用的字节数决定;该次数据报的负载数据

注:1.消息头可以出现零个或多个,但最多不能超过 127 个消息头 2.消息头 key 和 value 的长度均不能超过 127 个字节

整体调用流程

为了方便描述,后续报文内容按照结构体的方式展示,具体实现时需要按照规则进行编码

心跳

客户端连接上 sekiro 服务器之后如果超过一定时间未进行读写,服务器会发送心跳包给该客户端,客户端在接受到心跳包时必须回应服务端一个数据包, 否则服务端将主动断开该连接。当前版本服务端发送的心跳包与客户端响应的心跳包一致,报文结构大致如下:

struct{
    magic: sekiro01
    total_leng: 6
    type: 0x00
    seq_id: -1
    header_size: 0 
}

该结构按照规则编码后就是一个心跳包,客户端在实现时如果发现 type 为 0x00,可将该包原样返回给服务端。

注册 group

客户端在连接上服务端后的第一件事向服务端注册 group,这样服务端才能下发相应 group 的请求。客户端注册 group 报文结构大致如下:

    magic: sekiro01
    total_leng: 50
    type: 0x10
    seq_id: -1
    header_size: 2
    SEKIRO_CLIENT_ID:12345678
    SEKIRO_GROUP: test

50(total_leng) = 1(type)+ 4(seq_id) + 1(header_size) + 1(key_length)+16("SEKIRO_CLIENT_ID")+1(value_length)+8("1234567") +1(key_length)+12("SEKIRO_GROUP")+1(value_length)+4("test") + 0(data) 上面展示了该数据报 total_leng 字段值的计算方式。这个数据包发送给服务端之后就标示该客户端的 clientId 为 12345678,group 为 test, 当服务器接受到 group 为 test 的请求任务时将会下发给该客户端

接受服务器请求

注册完成之后服务端在接受到任务之后会下发请求,请求报文格式大致如下:

    magic: sekiro01
    total_leng: ?
    type: 0x20
    seq_id: 1
    data: "{"action":"test","a":""b","c":"d"}"

https://sekiro.iinti.cn/business/invoke?group=test&action=test&a=b&c=d

在浏览器请求该地址,sekiro 客户端就会接收到上面的报文内容。tatal_leng ?代替,并非实际值。该次请求报文的 seq_id 为 1,那么接受到该请求后对该请求的响应报文 seq_id 也需要设置为 1。

响应 Json 格式

sekiro 商业版响应 Json 时为了服务器不做 Json 解析但需要感知业务是否成功,数据包中的负载数据 data 内容并不是简单的 Json 字符串,有自己的编码规则; 编码格式如下:

SekiroProtocol

  • status: 状态,占4个字节;0 代表成功,1 代表失败
  • msgLength: 占 4 字节,值表示附带信息字符串占用的字节数,为 0 代表没有 msg
  • msg:附带信息
  • stringLength, 占 4 字节,值表示后续字符串占用的字节数
  • json string: 需要返回给业务的 json 字符串

接受到请求后需要进行响应,响应报文结构大致如下:

    magic: sekiro01
    total_leng: ?
    type: 0x20
    seq_id: 1
    PAYLOAD_CONTENT_TYPE:CONTENT_TYPE_SEKIRO_FAST_JSON
    data: 按规则编码

响应 Json 需要加入 PAYLOAD_CONTENT_TYPE:CONTENT_TYPE_SEKIRO_FAST_JSON 消息头表明负载数据格式。

答问:netty的lib为什么会重新修改包名,然后源码引入

这是因为netty是一个很底层的、API表面积过大、API多版本一致性较差的lib库,从这个方向来说netty不是一个优良的lib设计,然而netty在网络编程上的深度和沉淀方面又是非常强悍的, 他也算是世界顶级的项目。

这导致存在大量的其他sdk或者中间件服务会依赖netty,此时我们很容易发现多个lib共同依赖了netty,但是又是依赖的不同的netty版本。 这会导致有很大可能存在依赖冲突(选择任何一个版本的netty,会导致另一个lib报错)。这是因为不同netty版本提供的api不兼容。

这是在工程实践上遇到过多次的现象,实际上在遇到这个问题的时候需要很有经验调整各种lib库的版本,或者做一些源码hack操作。

而sekiro的场景一般运行在受限环境,比如Xposed环境下可能出现代码和宿主环境的netty不一致,但是受限环境我们无法调整netty版本。此时可能是一个无解的现状, 故Sekiro在sdk设计的时候,变将netty的源码copy了一份出来,然后修改了其包结构。这样sekiro使用的netty就是一个私有的netty发行版本,他永远不会导致依赖冲突

上次编辑于:
贡献者: liguobao