使用 QNX 实时操作系统实时接收 UDP 数据包
Realtime receiving of UDP packets with QNX RTOS
>我有一个源,它以 819.2 Hz(~1.2ms)的速率向我的 QNX Neutrino 机器发送 UDP 数据包。我希望以尽可能少的延迟和抖动接收和处理这些消息。
我的第一个代码基本上是:
SetupUDPSocket();
while (true) {
recv(socket, buffer, BufferSize, MSG_WAITALL); // blocks until whole packet is received
processPacket(buffer);
}
问题是 recv() 只在系统的每个计时器滴答时检查是否有新数据包可用。计时器时钟周期通常为 1 毫秒。因此,如果我使用它,我会得到巨大的抖动,因为我每 1 毫秒或每 2 毫秒处理一个数据包。我可以重置计时器时钟周期的大小,但这会影响整个系统(以及其他进程的其他计时器等)。而且我仍然会有抖动,因为我肯定永远不会完全匹配 819.2 Hz。
所以,我尝试使用网卡(5)的中断线。但似乎还有其他因素导致中断上升。我曾经使用以下代码:
ThreadCtl(_NTO_TCTL_IO, 0);
SIGEV_INTR_INIT(&event);
iID = InterruptAttachEvent(IRQ5, &event, _NTO_INTR_FLAGS_TRK_MSK);
while(true) {
if (InterruptWait(0, NULL) == -1) {
std::cerr << "errno: " << errno << std::endl;
}
length = recv(socket, buffer, bufferSize, 0); // non-blocking this time
LogTimeAndLength();
InterruptUnmask(IRQ5, iID;
}
这会导致在开始时进行一次成功的读取,然后在 0 次传递后以 0 字节长度读取。看起来,在执行 InterruptUnmask() 之后,InterruptWait() 根本不会等待,所以一定已经有一个新的中断(或者相同的?!
是否可以用网卡的中断线做类似的事情?是否还有其他可能性以 819.2 Hz 的速率接收数据包?
有关网卡的一些信息:"PCI -VVV"输出:
Class = Network (Ethernet)
Vendor ID = 8086h, Intel Corporation
Device ID = 107ch, 82541PI Gigabit Ethernet Controller
PCI index = 0h
Class Codes = 020000h
Revision ID = 5h
Bus number = 4
Device number = 15
Function num = 0
Status Reg = 230h
Command Reg = 17h
I/O space access enabled
Memory space access enabled
Bus Master enabled
Special Cycle operations ignored
Memory Write and Invalidate enabled
Palette Snooping disabled
Parity Error Response disabled
Data/Address stepping disabled
SERR# driver disabled
Fast back-to-back transactions to different agents disabled
Header type = 0h Single-function
BIST = 0h Build-in-self-test not supported
Latency Timer = 40h
Cache Line Size= 8h un-cacheable
PCI Mem Address = febc0000h 32bit length 131072 enabled
PCI Mem Address = feba0000h 32bit length 131072 enabled
PCI IO Address = ec00h length 64 enabled
Subsystem Vendor ID = 8086h
Subsystem ID = 1376h
PCI Expansion ROM = feb80000h length 131072 disabled
Max Lat = 0ns
Min Gnt = 255ns
PCI Int Pin = INT A
Interrupt line = 5
CPU Interrupt = 5h
Capabilities Pointer = dch
Capability ID = 1h - Power Management
Capabilities = c822h - 28002000h
Capability ID = 7h - PCI-X
Capabilities = 2h - 400000h
Device Dependent Registers:
0x040: 0000 0000 0000 0000 0000 0000 0000 0000
...
0x0d0: 0000 0000 0000 0000 0000 0000 01e4 22c8
0x0e0: 0020 0028 0700 0200 0000 4000 0000 0000
0x0f0: 0500 8000 0000 0000 0000 0000 0000 0000
和"nicinfo"输出:
wm1:
INTEL 82544 Gigabit (Copper) Ethernet Controller
Physical Node ID ........................... 000E0C C5F6DD
Current Physical Node ID ................... 000E0C C5F6DD
Current Operation Rate ..................... 100.00 Mb/s full-duplex
Active Interface Type ...................... MII
Active PHY address ....................... 0
Maximum Transmittable data Unit ............ 1500
Maximum Receivable data Unit ............... 0
Hardware Interrupt ......................... 0x5
Memory Aperture ............................ 0xfebc0000 - 0xfebdffff
Promiscuous Mode ........................... Off
Multicast Support .......................... Enabled
感谢您的阅读!
我不确定为什么声明"问题是 recv() 只在系统的每个计时器滴答声时检查是否有新数据包可用。计时器时钟周期通常为 1 毫秒",对于抢占式操作系统来说是正确的。系统配置中一定有问题,或者网络协议栈实现存在一些问题。
几年前,当我为雅虎BB日本公司做一些IPTV机顶盒项目时,我在RTP接收方面遇到了问题。问题不在于延迟或抖动,而在于我们添加一些NDS算法后机顶盒的整体系统性能。我们使用的是 vxWorks,vxWorks 支持以太网挂钩接口,每次驱动程序收到以太网数据包时都会调用该接口。
我将一个 API 挂接到其中,然后直接从以太网数据包中解析具有指定端口的 UDP。当然,我们有一些假设,即没有碎片,这是由性能问题的网络设置保证的。也许您也可以检查一下是否可以在 QNX 以太网驱动程序中获得相同的钩子。至少,您可以确定抖动是否来自驱动程序。
您的 UDP 数据包有多大? 如果数据包大小较小,您可以通过将更多数据打包到单个数据包中并降低传输速率来获得更高的效率。
我怀疑中断服务路由(ISR)没有屏蔽中断。也许它是为边缘敏感而设计的,而中断是电平敏感的。
我参加聚会有点晚了,但我遇到了你的问题,发现它与我遇到的情况相似。您可以尝试使用信号进行软件中断,而不是硬件中断。QNX 这里有一些文档:http://www.qnx.com/developers/docs/qnx_4.25_docs/qnx4/sysarch/microkernel.html#IPCSIGNALS 。我当时使用的是 CentOS,但理论是一样的。根据 http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/lib_ref/s/socket.html 您可以使用 ioctl() 为给定文件描述符的 SIGIO 信号设置接收组......在您的情况下是 UDP 套接字。当套接字有准备好读取的数据时,SIGIO信号将发送到ioctl()指示的进程。使用 sigaction() 告诉操作系统要使用什么信号处理函数。在您的情况下,信号处理程序可以从套接字读取数据并将其存储在缓冲区中进行处理。使用 pause() 暂停进程,直到它处理 SIGIO 信号。当信号处理程序返回时,进程将唤醒,你可以处理缓冲区中的数据。这应该允许您在数据传入时处理数据,而无需处理计时器或硬件中断。需要注意的一件事是,您的系统可以像UDP流量进入一样快地处理这些信号。
- 发送固定大小的 UDP 数据包
- 使用C++将UDP数据包存储在Structure中
- 在高数据包速率下最大限度地减少丢弃的 UDP 数据包 (Windows 10)
- Qt 在可预测的秒数后跳过 UDP 数据包
- 高频接收UDP数据包:丢包?
- 为 posix recv 设置超时会导致 udp 数据包丢失吗?
- 了解 UDP 数据包大小限制的 TCP 数据包大小限制以及它在 boost::asio 编程级别的含义
- 获取进入UDP数据包的目标端口
- 操纵Windows Explorer窗口时,UDP数据包会掉落
- C++ 使用 recvmmsg 丢弃 UDP 数据包
- 如何在QT中接收适当的UDP数据包
- 使用ASIO捕获大量UDP数据包
- 如何正确接收多播UDP数据包
- 服务器未收到UDP数据包,花费数小时试图找出问题所在
- 当接收缓冲区几乎满时,阻止UDP数据包被部分截断
- 如何检查UDP数据包是否在发送器上发送
- 使用 QNX 实时操作系统实时接收 UDP 数据包
- 高效地发送UDP数据包流
- 为什么我在使用 winsock 时没有收到 UDP 数据包?
- SDL_net UDP 数据包数据