📜  从通过网络发送的数据包中解码消息(1)

📅  最后修改于: 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 等,也可以自己定义格式。在解析数据时,需要根据约定的格式,将二进制数据转换成可读的数据结构。