【问题标题】:Network receipt timer to ms resolution网络接收计时器到毫秒分辨率
【发布时间】:2010-10-14 19:06:43
【问题描述】:

我的场景,我正在收集网络数据包,如果数据包与网络过滤器匹配,我想记录连续数据包之间的时间差,最后一部分是不起作用的部分。我的问题是,无论我使用什么 C 计时器功能,我都无法获得准确的亚秒级测量结果。我尝试过:gettimeofday()、clock_gettime() 和 clock()。

我正在寻求帮助以找出我的计时代码无法正常工作的原因。

我在 cygwin 环境中运行。 编译选项:gcc -Wall capture.c -o capture -lwpcap -lrt

代码 sn-p:

/*globals*/
int first_time = 0;
struct timespec start, end;
double sec_diff = 0;

main() {
  pcap_t *adhandle;
  const struct pcap_pkthdr header;
  const u_char *packet;
  int sockfd = socket(PF_INET, SOCK_STREAM, 0);

      .... (previous I create socket/connect - works fine)

  save_attr = tty_set_raw();

  while (1) {  

    packet = pcap_next(adhandle, &header);     // Receive a packet? Process it
    if (packet != NULL) {
      got_packet(&header, packet, adhandle);
    }

    if (linux_kbhit()) {         // User types message to channel
      kb_char = linux_getch();       // Get user-supplied character
      if (kb_char == 0x03)         // Stop loop (exit channel) if user hits Ctrl+C
        break;
    }
  } 
  tty_restore(save_attr);
  close(sockfd);
  pcap_close(adhandle);
  printf("\nCapture complete.\n");
}

在 got_packet 中:

got_packet(const struct pcap_pkthdr *header, const u_char *packet, pcap_t * p){    ... {

   ....do some packet filtering to only handle my packets, set match = 1
  if (match == 1) {
    if (first_time == 0) {
      clock_gettime( CLOCK_MONOTONIC, &start );
      first_time++;
    }
    else {
      clock_gettime( CLOCK_MONOTONIC, &end );

      sec_diff = (end.tv_sec - start.tv_sec) + ((end.tv_nsec - start.tv_nsec)/1000000000.0);  // Packet difference in seconds

      printf("sec_diff: %ld,\tstart_nsec: %ld,\tend_nsec: %ld\n", (end.tv_sec - start.tv_sec), start.tv_nsec, end.tv_nsec);
      printf("sec_diffcalc: %ld,\tstart_sec: %ld,\tend_sec: %ld\n", sec_diff, start.tv_sec, end.tv_sec);
      start = end;         // Set the current to the start for next match
    }
  }
}

我用 Wireshark 记录所有数据包以进行比较,所以我希望我的计时器的差异与 Wireshark 的相同,但事实并非如此。我的 tv_sec 输出是正确的,但是 tv_nsec 甚至还没有接近。假设wireshark有0.5秒的差异,我的计时器会说有1.999989728秒的差异。

【问题讨论】:

    标签: c sockets network-programming timer


    【解决方案1】:

    基本上,您需要使用带有higher resolution 的计时器

    另外,我没有签入 libpcap,但我很确定 libpcap 可以为您提供收到每个数据包的时间。在这种情况下,它将最接近 Wireshark 显示的内容。

    【讨论】:

    • 事实证明,你是对的 - libpcap 确实可以处理它。在我的 got_packet 函数中,我传递了 const struct pcap_pkthdr *header,它在收到数据包时包含 sec 和 usec 分辨率。我称之为:header->ts.tv_sec,header->ts.tv_usec,它给了我最好的时机。
    【解决方案2】:

    我不认为时钟是您的问题,而是您等待新数据的方式。您应该使用轮询功能来查看何时从套接字或键盘获得新数据。这将使您的程序在没有新数据要处理时进入睡眠状态。当操作系统确实有数据要处理并更快地安排它时,这可能会使操作系统对您的程序更好。这也允许您退出程序,而不必等待下一个数据包进来。或者,您可以尝试以非常高或实时的优先级运行您的程序。

    如果过滤可能需要很长时间,您应该考虑在收到数据包后首先获取当前时间。如果您尝试在快速且繁忙的网络上捕获数据,您可能还需要为该程序考虑多个线程。特别是如果您有多个处理器,但由于您正在执行一些可能会阻塞的pritnfs。我注意到您有一个将 tty 设置为原始模式的功能,我认为这是标准输出 tty。如果您实际上使用的串行终端可能会大大降低速度,但标准输出到 xterm 也可能很慢。您可能需要考虑将stdout 设置为完全缓冲而不是行缓冲。这应该加快输出。 (man setvbuf)

    【讨论】:

    • 如果我错了,请纠正我,但我认为我的主要 while 语句正在执行您描述的轮询,我查看数据包是否到达或者用户是否输入了退出字符然后对其进行操作。我怎样才能以更少的资源使用来做到这一点?
    • 轮询函数,如pollselect, and epoll` 让您的程序在等待新输入时进入睡眠状态。 Linux(linux_kbhit 泄露了您使用的操作系统)有时会通过降低其动态优先级和/或提高执行大量睡眠的进程的动态优先级(当您等待 IO 或致电pause()nanosleep())。
    猜你喜欢
    • 2018-06-01
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    相关资源
    最近更新 更多