我需要编写一个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 举报,一经查实,本站将立刻删除。