Linux TCP套接字时间戳选项

5

引用自在线内核文档

  • SO_TIMESTAMPING 在接收、传输或两者均生成时间戳。支持多个时间戳源,包括硬件。支持为套接字生成时间戳。

Linux支持TCP时间戳,并尝试编写一些演示代码以获取TCP数据包的任何时间戳。

以下是服务器端代码:

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
    perror("bind failed. Error");
    return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
int c = sizeof(struct sockaddr_in);

client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
    perror("accept failed");
    return 1;
}

// Note: I am trying to get software timestamp only here..
int oval = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
int olen = sizeof( oval );
if ( setsockopt( client_sock, SOL_SOCKET, SO_TIMESTAMPING, &oval, olen ) < 0 )
    { perror( "setsockopt TIMESTAMP"); exit(1); }

puts("Connection accepted");

char    buf[] = "----------------------------------------";
int len = strlen( buf );

struct iovec    myiov[1] = { {buf, len } };

unsigned char   cbuf[ 40 ] = { 0 };
int     clen = sizeof( cbuf ); 

struct msghdr   mymsghdr = { 0 };
mymsghdr.msg_name   = NULL;
mymsghdr.msg_namelen    = 0;
mymsghdr.msg_iov    = myiov;
mymsghdr.msg_iovlen = 1;
mymsghdr.msg_control    = cbuf;
mymsghdr.msg_controllen = clen;
mymsghdr.msg_flags  = 0;

int read_size = recvmsg( client_sock, &mymsghdr, 0);

if(read_size == 0)
{
  puts("Client disconnected");
  fflush(stdout);
}
else if(read_size == -1)
{
  perror("recv failed");
}
else
{
  struct msghdr *msgp = &mymsghdr;
  printf("msg received: %s \n",(char*)msgp->msg_iov[0].iov_base);// This line is successfully hit.
  // Additional info: print msgp->msg_controllen inside gdb is 0.
  struct cmsghdr    *cmsg;
  for ( cmsg = CMSG_FIRSTHDR( msgp );
      cmsg != NULL;
      cmsg = CMSG_NXTHDR( msgp, cmsg ) )
  {
    printf("Time GOT!\n"); // <-- This line is not hit.
    if (( cmsg->cmsg_level == SOL_SOCKET )
        &&( cmsg->cmsg_type == SO_TIMESTAMPING ))
      printf("TIME GOT2\n");// <-- of course , this line is not hit
  } 

有没有想法为什么这里没有时间戳?谢谢。

解决方案 我能够使用solarflare NIC的onload获得软件时间戳和硬件时间戳。 但仍不清楚如何单独获取软件时间戳。


我怀疑 SO_TIMESTAMPING 是与 cmsg_type 匹配的正确值。 - user933161
抱歉,我没听懂您的意思。能否请您详细说明一下? - FaceBro
暂时不用管它。还有其他问题。请打开所有警告并编译您的代码,分享构建输出以及程序输出。 - user933161
这只是整个服务器代码的一部分,你可以轻松地使其可构建。 - FaceBro
@Igor,啊,我明白你第一条评论的意思了。但问题在于首先没有与cmsg_type匹配的cmsg,没有返回控制消息。 - FaceBro
Facebro,你是否曾经通过内核获取TCP的RX时间戳? - user997112
1个回答

2
您提供的链接,在评论末尾中说:
I've discovered why it doesn't work. SIOCGSTAMP only works for UDP
packets or RAW sockets, but does not work for TCP. – Gio Mar 17 '16 at 9:331    

it doesn't make sense to ask for timestamps for TCP, because there's
no direct correlation between arriving packets and data becoming 
available. If you really want timestamps for TCP you'll have to use 
RAW sockets and implement your own TCP stack (or use a userspace TCP
library). – ecatmur Jul 4 '16 at 10:39 

我在内核文档的末尾没有找到你提到的评论。实际上,我已经仔细阅读了该文档多次,在第1.4节中有解释支持TCP时间戳。 - FaceBro
我认为上面的链接末尾没有评论。你能告诉我在哪里找到上面的评论吗? 1.4节清楚地说明了TCP时间戳得到了支持。 - FaceBro
1
这个答案来自另一个SO线程https://dev59.com/xZXfa4cB1Zd3GeqPaiI5 我非常怀疑这些评论的权威性。需要更多的权威来源。 - FaceBro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接