📅  最后修改于: 2023-12-03 15:36:20.842000             🧑  作者: Mango
在网络通信中,二进制数据通常是通过数据包传输的。为了使通信双方能够理解这些数据,需要约定一种数据格式和打包方式。常见的数据格式包括 JSON、XML、Hessian、Thrift 等。当然,你也可以定义自己的数据格式。
网络数据通常是通过 Socket 连接发送和接收的。发送方在发送数据前,需要对数据进行打包,接收方在接收数据后,需要对数据进行解包。打包和解包的时候需要遵循一定的规则,如数据长度的表示、字节序等。
以下是一个简单的示例,演示如何将字符串打包成二进制数据:
import struct
def pack_string(data):
# 计算数据长度
length = len(data)
# 使用网络字节序,表示整数为大端字节序
format = '!I%ds' % length
# 打包数据
packed_data = struct.pack(format, length, data)
return packed_data
这段代码通过 struct
模块将字符串打包成二进制数据。首先计算字符串长度,然后使用 !I%ds
格式串,表示一个 unsigned int 整数和一段字符串。!
表示使用网络字节序,I
表示使用 4 字节表示整数。打包后的数据格式为:
+--------+-------------+
| 4 bytes| n bytes |
+--------+-------------+
| length | data |
+--------+-------------+
接收方需要按照同样的格式解包数据。以下是解包的示例代码:
def unpack_string(packed_data):
# 解包整数和字符串
# 根据前四个字节,即长度,计算出字符串的结束位置
length = struct.unpack('!I', packed_data[:4])[0]
data = struct.unpack('!%ds' % length, packed_data[4:])[0]
return data
这段代码首先使用 !I
格式串,解包前四个字节表示的整数,然后根据整数计算出字符串的结束位置。最后使用 !%ds
格式串,解包出字符串。需要注意的是,解包出的字符串是按字节处理的,需要使用 decode()
方法转换成 Unicode 字符串。
接收方解包出二进制数据后,需要进一步解析数据。根据约定好的数据格式,将二进制数据转换成可读的数据结构。
以下是一个使用 JSON 格式的示例,在接收方和发送方之间传输字典对象。
import json
def send_json_data(sock, data):
json_data = json.dumps(data)
packed_data = pack_string(json_data.encode())
sock.sendall(packed_data)
这段代码首先将字典对象转换成 JSON 字符串,然后将字符串编码成二进制数据,最后使用前面定义的打包函数打包数据,发送到 Socket 连接。
def receive_json_data(sock):
# 读取数据长度
length_data = sock.recv(4)
data_length = struct.unpack('!I', length_data)[0]
# 读取数据
data = b''
while len(data) < data_length:
recv_data = sock.recv(data_length - len(data))
if not recv_data:
raise ConnectionError('Connection closed')
data += recv_data
# 解包数据,转换成 JSON 对象
json_data = unpack_string(data).decode()
return json.loads(json_data)
这段代码首先读取前四个字节,计算数据长度。然后使用循环读取数据,直到读取到指定长度的数据为止。读取完后,使用前面定义的解包函数解包数据,然后将 JSON 字符串转换成 Python 对象。
通过网络发送数据时,需要进行打包和解包,以便通信双方能够正确理解数据。在定义数据格式时,可以使用常见的格式,如 JSON、XML 等,也可以自己定义格式。在解析数据时,需要根据约定的格式,将二进制数据转换成可读的数据结构。