我需要为 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/