1

对于我正在努力解决的问题,标题可能非常不正确。

我试图以我理解的方式解释我从赛车游戏中收到的数据包,但老实说,我真的不知道我在看什么,或者搜索什么来理解它。我在这里收到的数据包信息: https ://forums.codemasters.com/topic/54423-f1%C2%AE-2020-udp-specification/?tab=comments#comment-532560

我正在使用 python 来打印数据包,这是输出的一个片段,我不明白如何解释。

收到消息:b'\xe4\x07\x01\x03\x01\x07O\x90.\xea\xc2!7\x16\xa5\xbb\x02C\xda\n\x00\x00\x00\xff\x01\x00 \x03:\x00\x00\x00 A\x00\x00\xdcB\xb5+\xc1@\xc82\xcc\x10\t\x00\xd9\x00\x00\x00\x00\x00\x12\x10\x00\ x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$tJ\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ x00\x00\x00\x01

我对编码很陌生,不确定下一步是什么,所以朝着正确的方向轻推将有助于加载,谢谢。

这是python代码:

import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 20777
sock = socket.socket(socket.AF_INET, # Internet
              socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
    data, addr = sock.recvfrom(4096)
    print ("received message:", data)
4

2 回答 2

2

您链接到的网站正在描述数据格式。所有数据都表示为一系列 1 和 0。一个字节是一系列 8 个 1 和 0。然而,仅仅因为你有一系列字节并不意味着你知道如何解释它们。它们代表一个角色吗?一个整数?这个整数可以是负数吗?所有这些都是由首先制作数据的人定义的。

您在顶部看到的类型描述告诉您如何实际解释这一系列 1 和 0。当您看到“unit8”时,它是一个“8 位(1 字节)长的无符号整数”。换句话说,一个介于 0 和 255 之间的正数。另一方面,“int8”是一个“8 位整数”,或者可以是正数或负数的数字(因此范围是 -128 到 127)。相同的基本思想适用于 *16 和 *64 变体,只有 16 位或 64 位。float 表示一个浮点数(带有小数部分的数字,例如 1.2345),一般为 4 个字节长。此外,您需要知道解释单词中字节的顺序(从左到右或从右到左)。这被称为字节顺序,

鉴于所有这些,您可以解释 PacketHeader。最简单的方法可能是struct在 Python 中使用包。详细信息可以在这里找到: https ://docs.python.org/3/library/struct.html

作为概念证明,以下将解释前 24 个字节:

import struct
data = b'\xe4\x07\x01\x03\x01\x07O\x90.\xea\xc2!7\x16\xa5\xbb\x02C\xda\n\x00\x00\x00\xff\x01\x00\x03:\x00\x00\x00 A\x00\x00\xdcB\xb5+\xc1@\xc82\xcc\x10\t\x00\xd9\x00\x00\x00\x00\x00\x12\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$tJ\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'

#Note that I am only taking the first 24 bytes. You must pass data that is
#the appropriate length to the unpack function. We don't know what everything 
#else is until after we parse out the header
header = struct.unpack('<HBBBBQfIBB', data[:24])
print(header)

您基本上想读取前 24 个字节以获取消息的标头。从那里,您需要使用该m_packetId字段来确定消息的其余部分是什么。例如,此特定数据包的 packetId 为 7,即“汽车状态”数据包。因此,您将在struct CarStatus该页面的下方查看打包格式,以了解如何解释消息的其余部分。数据到达时冲洗并重复。

更新:在格式字符串中,<告诉您将字节解释为不对齐的小端(基于文档说它是小端和打包的事实)。我建议通读上面文档中有关格式字符的整个部分,以充分了解有关对齐的所有情况,但简而言之,它将尝试将这些字节与其在内存中的表示对齐,这可能与您的格式不完全匹配指定。在这种情况下,HBBBBQ占用的字节数比您预期的多 2 个字节。这是因为您的计算机将尝试将结构打包到内存中,以便它们是字对齐的。您的计算机体系结构决定了字对齐(在 64 位计算机上,字是 64 位或 8 字节长)。一种Q需要一个完整的单词,因此打包器将尝试将 Q 之前的所有内容与一个单词对齐。但是,HBBBB只需要 6 个字节;因此,默认情况下,Python 将额外填充 2 个字节以确保所有内容都对齐。在前面使用<都可以确保以正确的顺序解释字节,并且不会尝试对齐字节。

于 2020-07-08T02:33:54.790 回答
0

仅供参考,如果其他人正在寻找这个。在 python 中有库f1-2019-telemetry存在。在文档中,缺少关于“如何使用”的部分,所以这里有一个片段:

from f1_2020_telemetry.packets import *
...

udp_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
udp_socket.bind((host, port))

while True:
    udp_packet = udp_socket.recv(2048)
    packet = unpack_udp_packet(udp_packet)

    if isinstance(packet, PacketSessionData_V1):  # refer to doc for classes / attribute
        print(packet.trackTemperature) # for example
    if isinstance(packet, PacketParticipantsData_V1):
        for i, participant in enumerate(packet.participants):
            print(DriverIDs[participant.driverId]) # the library has some mapping for pilot name / track name / ...

问候,

尼古拉斯

于 2020-07-25T09:01:03.537 回答