在阅读
此处
、
此处
和
此处
时,我发现在Linux系统上,您可以通过设置套接字选项来请求接收和传输的数据包的时间戳。我目前可以使用
SO_TIMESTAMPNS
和
SO_TIMESTAMPING
来通过
recvmsg
获取 Rx 时间戳。使用
sendmsg
我不知道如何正确打包控制消息的辅助数据,并且 sendmsg 甚至没有可以保存我需要的数据的返回。
这就是我获取 Rx 时间戳的方式.
import socket
SO_TIMESTAMPING = 37
SOF_TIMESTAMPING = 127
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPING, SO_TIMESTAMPING, SOF_TIMESTAMPING)
server_sock.bind((_svr_ip, _svr_port))
server_sock.listen(_num_clients)
conn, client_addr = server_sock.accept()
msg, ancdata, flags, address = conn.recvmsg(64, 1024)
t_rx = ancdata[0][2]
t_rx_s = int.from_bytes(t_rec[0:7], byteorder="little")
t_rx_ns = int.from_bytes(t_rec[8:], byteorder="little")
第 1.3.4 节
提到通过控制消息启用时间戳,而不必使用
socket.setsockopt
来保留开销。我相信这意味着您在调用
sendmsg
而不是使用
socket.setsockopt
时将标志添加到控制消息中。
很遗憾,你不能直接使用
socket.sendmsg
获取 Python 中的套接字 Tx 时间戳。
你对 Linux 套接字时间戳的理解是正确的。虽然你可以包含
SOF_TIMESTAMPING
控制消息以在每个数据报的基础上启用时间戳,但这仅适用于
接收
时间戳,使用
recvmsg
检索。
原因:
-
Tx 时间戳是在数据包离开网络接口时生成的
,这发生在 Python 网络堆栈之外的内核中。当你调用
sendmsg
时,数据会被复制到内核缓冲区,而时间戳是在稍后的某个时间点异步生成的。 -
sendmsg
不提供检索此未来时间戳的机制。 它主要用于发送数据,并且控制消息用于设置套接字选项或附加辅助数据(如接收时间戳)。
备选方案:
-
使用
SO_TIMESTAMPNS
recvmsg
: 尽管你不能在sendmsg
中获取 Tx 时间戳,但如果你在接收端也控制着应用程序,则可以使用SO_TIMESTAMPNS
和recvmsg
来获取接收时间戳。这为你提供了数据包传输时间的近似值。 -
使用数据包嗅探器: 如果你需要更精确的 Tx 时间戳,请使用
tcpdump
或Wireshark
之类的外部工具。这些工具可以直接从网络接口捕获数据包并提供准确的时间戳。 -
使用更底层的网络库: 考虑使用
scapy
或dpkt
之类的库,这些库提供了对原始套接字和数据包操作的更多控制。使用这些库,你可能可以实现自定义时间戳机制,但它需要更深入地了解网络编程。
结论:
虽然 Python 的
socket
模块提供了对套接字时间戳的良好支持,但它不直接提供对
sendmsg
的 Tx 时间戳的访问权限。你可以探索上述备选方案来实现你的目标,具体取决于你的特定需求和约束。