通过套接字文件描述符上的ioctl调用获取数据包时间戳

我正在研究运行嵌入式Linux的系统。 我正在尝试从我在套接字上收到的流中获取数据包时间戳。

创建套接字后,我执行以下操作:

if (fd != -1) { int enabled = 1; setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &enabled, sizeof(enabled); } 

之后我绑定套接字,套接字的类型为SOCK_STREAM。 我通过调用函数recv(fd, buf, size, 0)成功接收套接字上的数据。 现在,为了获取接收数据的时间戳,我目前正在尝试以下方法:

 ret = recv(fd, buf, size, 0); if (ret > 0) { struct timeval tv_ioctl; tv_ioctl.tv_sec = 0; tv_ioctl.tv_usec = 0; int error = ioctl(fd, SO_TIMESTAMP, &tv_ioctl); printf("%ld.%ld - error = %d", (long int)tv_ioctl.tv_sec, (long int)tv_ioctl.tv_usec, error); } 

printf语句的输出始终如下:

0.0错误= -1

错误= -1表示ioctl调用失败。 我用getsockopt执行了一个测试,检查是否设置了SO_TIMESTAMP选项, getsockopt为选项SO_TIMESTAMP返回0,所以看起来设置正确。 我在这里有点迷失,我怎么能进一步调查为什么ioctl调用似乎失败了?

用于检索套接字上最新时间戳的ioctl是SIOCGSTAMP ; SO_TIMESTAMP是一个套接字选项,而不是ioctl。 您的代码应为:

 int error = ioctl(fd, SIOCGSTAMP, &tv_ioctl); ^^^^^^^^^^ 

检索时间戳的另一种方法是将recv更改为recvmmsg并从辅助数据中提取时间戳。 这样更有效,因为它涉及更少的系统调用( 套接字读取和时间戳 ); 但是,ioctl更简单。

请注意,SIOCGSTAMP和SO_TIMESTAMP是互斥的 – 如果您要使用SIOCGSTAMP,则应禁用 SO_TIMESTAMP( enabled = 0 )。 这是因为SO_TIMESTAMP指示内核通过recvmmsg辅助数据而不是通过SIOCGSTAMP使时间戳可用。