利用 Python 存储和重放二进制网络数据

76 阅读3分钟

我有基于 Python 的应用程序,该应用程序会以 50 Hz 的速率通过网络发送 556 字节的数据。此二进制数据是由 struct.pack() 生成的,该函数会返回一个字符串,随后将该字符串写入 UPD 套接字。

除了传输这些数据外,我还希望以尽可能节省空间的方式将这些数据保存的文件中,包括每个消息的时间戳,以便我以后可以重放这些数据。使用 Python 完成此操作的最佳方法是什么?

我已经考虑使用日志记录对象,但我尚未找到 Python 是否能够读取日志文件以便我可以重放数据的答案。此外,我不知道日志记录对象是否可以处理二进制数据。

希望大家分享一些建议!虽然可以考虑使用 Wireshark,但还是更愿意使用我的应用程序存储数据,这样我就可以在每次运行程序时自动启动新的数据文件。

2、解决方案

方法一

Python 的日志记录系统旨在处理人类可读的字符串,并且它易于启用或禁用,具体取决于您(开发人员)或其他人是否正在运行程序。不要将它用于应用程序始终需要输出的内容。

存储数据的最简单方法是将您通过套接字发送的相同 556 字节字符串直接写入文件。如果您想具有时间戳,则可以在每个 556 字节消息前加上发送时间,将其转换为整数,并使用 struct.pack() 将其打包为 4 或 8 个字节。具体方法取决于您的特定要求,例如您需要时间有多精确,以及您需要绝对时间还是只能相对于某个参考点。

代码示例:

import socket
import struct
import time

# 创建 UDP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 设置目标地址和端口
target_addr = ('127.0.0.1', 5000)

# 生成二进制数据
data = struct.pack('>i', 1234)

# 创建文件用于存储数据
f = open('data.bin', 'wb')

# 循环发送数据并将其写入文件
while True:
    # 获取当前时间戳(以秒为单位)
    timestamp = time.time()

    # 将时间戳打包为二进制数据
    timestamp_bin = struct.pack('>d', timestamp)

    # 将时间戳和二进制数据写入文件
    f.write(timestamp_bin)
    f.write(data)

    # 将二进制数据发送到目标地址和端口
    sock.sendto(data, target_addr)

    # 延迟 20 毫秒,以匹配 50 Hz 的发送速率
    time.sleep(0.02)

# 关闭文件
f.close()

方法二

一种用于重放目的的紧凑时间戳的可能性是:使用 time.time() 将时间设置为自纪元以来的浮点数秒数,乘以 50(因为您说您每秒重复此操作 50 次,所得单位 1/50 秒有时称为“jiffy”),截断为整数,从您在程序开始时测量的类似时间戳中减去自纪元以来的 jiffy 数,并将结果使用 struct.pack() 打包为具有所需字节数的无符号整数。

代码示例:

import socket
import struct
import time

# 创建 UDP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 设置目标地址和端口
target_addr = ('127.0.0.1', 5000)

# 生成二进制数据
data = struct.pack('>i', 1234)

# 创建文件用于存储数据
f = open('data.bin', 'wb')

# 启动时间
start_time = time.time()

# 循环发送数据并将其写入文件
while True:
    # 获取当前时间戳(以秒为单位)
    timestamp = time.time()

    # 计算自启动时间以来的时间戳差值(以 jiffy 为单位)
    timestamp_diff = int((timestamp - start_time) * 50)

    # 将时间戳差值打包为二进制数据
    timestamp_bin = struct.pack('>H', timestamp_diff)

    # 将时间戳差值和二进制数据写入文件
    f.write(timestamp_bin)
    f.write(data)

    # 将二进制数据发送到目标地址和端口
    sock.sendto(data, target_addr)

    # 延迟 20 毫秒,以匹配 50 Hz 的发送速率
    time.sleep(0.02)

# 关闭文件
f.close()