龙空技术网

python之TCP粘包对策及自定义pack和unpack

皛心 175

前言:

目前看官们对“java socketchannel粘包处理”大约比较珍视,大家都想要分析一些“java socketchannel粘包处理”的相关内容。那么小编在网络上搜集了一些关于“java socketchannel粘包处理””的相关资讯,希望同学们能喜欢,同学们快快来了解一下吧!

什么是粘包问题?

因为TCP协议是流式协议所以数据包之间没有边界,有时会因为操作系统缓存机制、网络延迟等原因造成2次间隔时间较短、数据量较少的数据合并成一次发送。因此影响了数据的完整性。

粘包问题解决策略:

常见的解决方式是通过自定义协议厘清数据包之间的边界。

发送方

1.发送数据包前先计算长度,再将int型长度数据转换成4字节的bytes型;

2.先发送4字节bytes型长度数据,再发送数据包。

接收方

1.先接收4字节bytes型长度数据,将其转换成int型长度数据。

2.只接收指定长度的数据。

以上协议是服务端和终端双方均要遵守的自定义协议。这样就可以解决粘包问题。

区分消息和文件

通常而言消息大小设为1024字节,发送消息前要先发送消息的长度,然后再发消息。接收时也是要先接收长度,再接收消息。

发送文件时要先计算文件的大小,然后发送文件的长度,再发送文件。接收时要先接收文件的大小,socket文件收发缓存大小通常设为65535。注意:文件发送时发送方发送的数据包大小是固定的,但接收方每次收到的数据包大小不固定,每次接收后要用文件长度减去接收到的数据包长度,判断剩余未接收文件长度小于1才算完成。

stuct模块pack和unpack缺陷

处理粘包问题我查阅了很多资料,看到绝大多数人都是import struct,使用struct.pack和unpack来完成int数据与bytes相互转换的工作。但是我觉得struct模块的pack和unpack有2个缺陷:一是表示数值范围是-2147483648至2147483647,负值在计算数据长度完全用不上,会造成上传、下载文件大小不能超过2个G,unpack返回的是一个元组,还要对元组解包才能使用。所以我尝试自己写了一个pack和unpack在下面分享给大家。

自定义pack和unpack

def pack(n):    if n >= 4294967296 or n < 0:        raise ValueError('The value is out of range.')    values = ((0b11111111000000000000000000000000, 24),              (0b111111110000000000000000, 16), (0b1111111100000000, 8), (0b11111111, 0))    ret = b''    for i in values:        x = (n & i[0]) >> i[1]        x = x.to_bytes(length=1, byteorder="big")        ret += x    return ret
def unpack(numlist):    if len(numlist) != 4:        raise ValueError("The bytes length must be 4.")    values = (24, 16, 8, 0)    ret = 0    i = 0    while i < 4:        n = numlist[i]        ret += n << values[i]        i += 1    return ret

代码说明:

自定义的pack函数表示范围是0-4294967295,上传、下载文件长度在4个g以内都不会报错。

在该函数中通过按位与配合位移算法以及python3内置函数to_bytes()来完成功能,不需要另外import。

自定义的unpack函数直接返回int型数值,不需要解包。在这个函数里全部是自定义的代码,没有引用任何函数也没有导包,通过位移运算完成bytes转换成int。

标签: #java socketchannel粘包处理