chrwhy / tcp_pack_demo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

tcp_pack_demo

这个demo是一种简便的解决方案用于解决TCP分包/粘包, 其实就是借鉴HTTP中header信息中所带的信息长度,可以将这个demo理解成一个应用层协议(当然这个demo只是最简单的示例)

TCP分包/粘包的问题, 本质上是同一个问题, 由于socket在发送或者接收数据的时候会等待缓冲区中的数据满了才会进行, 这个时候就会导致大包拆成多个小包, 或者多个小包被合成一个大包...

分包/粘包是不可避免的问题, 不管是在TCP层还是基于TCP之上的应用层,比如 HTTP 就采用了Content-Length 指定了数据的大小, 或者是 chunked 编码的方式, 还有回车换行 \r\n 分隔符...等等方式去避免/解决这个问题

tcp_pack_demo 是针对TCP分包/粘包的一种解决方案, 是在业务层定义的规范/协议针对这个问题的办法, 当然这不是唯一的办法, 比如还可以用换行符(或者约定的分隔符, JDK中socket相关的API就有readline()这样的方法进行解决)进行分隔......等等等等

这个demo的思路就是在业务数据前面附加一段 meta_data, 这个 meta_data (类似HTTP里头的 header)可以根据业务需要设置不同的元数据, 这个demo中meta_data只设置了真正的业务数据的长度, 比如业务上需要发送 "hello server" 这段数据, 这个时候需要在发送前计算一下这段字符的字节数为12, 如果我们定义meta_data的长度为4位(也可以更长, 更具业务需要定义规范/协议)在高位补 '0' 填充至4位即: 0012, 然后将 meta_data 拼在业务数据的前面, 那么数据将变成 "0012hello server"这样发送出去, 那么接收端在接收的时候会先读取前面4位(meta_data)以确定接下来需要从缓冲区中读取多少字节的数据......

后记更新

2018.08.24

发票圈后, 有朋友提醒 meta_data 指定长度部分可以使用二进制表示, 可以获得更大的长度支持, 这里更新说明一下, 其实传输的数据本质上是二进制流, 支持的长度取决于业务上把这个meta_data定义成什么类型的数据, 在这个 demo 中是使用了字符类型, 每个字符是一个字节, 一共4位(4个字节)能表达/支持的最大长度为9999, 如果我们用整形(struct类库)表达,同样是4个字节(32 bit)可表达的长度变成了2的32次方大小, 当然客户端和服务端之间需要协商好这样的协议, 在 python中是用 struct.pack() 和 stuct.unpack() 就可以完美实现, 可选择的类型有 int, unsigned int, long......等等等

为了保留2个版本对比, 使用 struct lib 对 meta length 进行改进的版本放在新的分支 meta_enhance 中, 这样可以对比理解.

About


Languages

Language:Python 100.0%