微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何每1毫秒发送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),(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检查,这使得数据包速度更慢。

C-在Windows中使用exec()

真正的并行下载

C ++ windows二进制文件:与MinGW一起使用的条件

如何find一个pthread是否有挂起的取消请求

铿锵C ++交叉编译器 – 从Mac OS X生成Windows可执行文件

我认为这应该是更优雅的方式,以不同的方式实现我的目标。 请提供build议。

如何避免在Linux系统标准的C / C + +库?

pipe理员权限

确定(以编程方式)谁使用C#或C ++在PC上控制鼠标

在Ubuntu 16.04上编译PCL 1.7,CMake中的错误生成了Makefile

gdborig.exe在debuggingQT 5.8和在Windows中打开QFileDialog时随机崩溃

在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”时钟的分辨率。

如果你希望它是一致的,你应该仿效你的进程到一个核心,并通过在底部的_mm_pause()在忙碌的循环中“烧”该核心。 然后你会在每个循环迭代中检查时钟,如果时间已经过去了,就要发送一个数据包。

如果你想保持一致,你应该从头开始计算时间,并在每次发送数据包时碰撞你的“下一个超时”变量。 但是要小心:当电脑进入休眠状态时,运行起来会很容易,然后再次唤醒,并认为是时候启动100000个数据包(只要问Adobe,他们在十年前在Flash中就有这个bug) 。

哦,显然不要在笔记本电脑或手机等功耗有限的设备上这样做。

您可以实现一个内核模式组件来发送UDP数据包,这可以避免用户和内核模式之间的上下文切换。 同时您可以访问高精度计时器几乎实时发送数据包。

使用2个线程。 主线程

pthread_mutex_lock(&sendLock); /* create worker thread to send packet */ while (counter < 4294967295) { pthread_mutex_unlock(&sendLock); /* nano sleep for very small interval */ sched_yield(); pthread_mutex_lock(&sendLock); /* nano sleep for remaining time interval */ }

同时在工作线程中

while (1) { pthread_mutex_lock(&sendLock); pthread_mutex_unlock(&sendLock); /* udp send code and counter increment*/ for (k=0; k<4; k++) //Convert counter value to string { buf[k]=((unsigned char*)(&counter))[k]; } sn = sendto(sender,sizeof(srv_addr)); // Sending UDP segment if (sn < 0 ) error("UDP send fail!"); //Error handle counter++; sched_yield(); }

这将有助于确保每个时间间隔发送一个数据包

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐