c - 如何每 1 毫秒发送一次 UDP 数据包?

标签 c linux sockets udp

我需要为 Linux 编写一个应用程序来定期发送 UDP 数据包。 理想情况下,频率应为每 1 毫秒一次,并且数据包之间的间隔应保持一致。

我试过用这种方式通过普通套接字来做到这一点:

while(counter < 4294967295)
{
    for (k=0; k<4; k++) //Convert counter value to string
    {
        buf[k]=((unsigned char*)(&counter))[k];
    }
    sn = sendto(sender, &buf, sizeof(buf), 0, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); // Sending UDP segment
    if (sn < 0 ) error("UDP send fail!"); //Error handle
    counter++;

    nanosleep(&delay, NULL); //Sleep
}

在上面的应用程序中,我只是用一个计数器值填充 UDP 数据包,所以我可以在接收端区分它们。

基本上这段代码完成了它的工作,但是有这些问题: 1.频率不够高,受主机性能和其他应用程序影响很大。 2.包间隔不一致,因为有RTC作为引用。但是,如果我尝试进行 RTC 检查,这会使数据包速率变得更慢。

我认为应该有更优雅的方式来通过不同的方法实现我的目标。请多多指教。

最佳答案

在 Linux(或与此相关的任何 UNIX)上获得重复定期心跳的标准方法是使用 setitimer(2):

#include <sys/time.h>
#include <signal.h>

struct itimerval timer;
timer.it_interval.tv_sec = timer.it_value.tv_sec = 0;
timer.it_interval.tv_usec = timer.it_value.tv_usec = 1000;   /* 1000 microseconds */
if (setitimer(ITIMER_REAL, &timer, 0) < 0) {
    perror("setitimer");
    exit(1); }

现在您将每毫秒收到一个 SIGALRM 信号,因此您可以使用 sigwait 调用运行循环:

sigset_t alarm_sig;
int signum;
sigemptyset(&alarm_sig);
sigaddset(&alarm_sig, SIGALRM);
while (1) {
    sigwait(&alarm_sig, &signum); /* wait until the next signal */
    ... do your stuff to send a packet, or whatever.
}

现在,只要系统能够保持正常运行,您就会每毫秒发送一个数据包。后者很重要——如果系统负载过重(或者您创建数据包的代码太慢),下一个信号将在下一个 sigwait 调用之前进入并终止您的进程。如果您不希望这样,请为 SIGALARM 信号添加一个信号处理程序:

void missed_alarm(int signum) {
    /* we missed a timer signal, so won't be sending packets fast enough!!! */
    write(2, "Missed Alarm!\n", 14); /* can't use printf in a signal handler */
}

signal(SIGALRM, missed_alarm);

现在,如果错过警报,您的数据包发送速度会变慢(您会错过一个时隙),但您会在 stderr 上收到有关它的消息。


上述内容的一个重要问题是它取决于您的系统计时器分辨率。在 Linux 上,这在很大程度上取决于内核配置 CONFIG_HIGH_RES_TIMERS。如果未启用,您可能只有 10 毫秒的分辨率,因此尝试使用 1 毫秒的时钟将严重失败。我相信它在大多数 x86_64 发行版上默认启用,但您可以通过查看/proc/timer_list 来检查并查看“ktime_get_real”时钟的分辨率。

关于c - 如何每 1 毫秒发送一次 UDP 数据包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25327519/

相关文章:

c++ - 为什么小数点后的数字都是零?

c++ - 如何将 WebAssembly 编译成常规汇编/ native 代码(或 Cpp 等)?

java - 通用套接字代理服务器也可以有效地与保持 Activity 连接一起工作(Java)

c - 判断条件语句中的单个语句为真

c - Linux 中的 PATH_MAX 定义在哪里?

c++ - 如何使用 SSE 指令?

C++通过命令行使用*字符传递多个文件

linux - 我在"Attempt to postMessage on disconnected port"安装扩展时出现"extensions.gnome.org"

android - 如何使用实时套接字正确终止 Android 应用程序

c - 加入多播组调用setsockopt报错 "No such device"