我有基于 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()