C++ QNX RTOS实时接收UDP数据包

C++ QNX RTOS实时接收UDP数据包,c++,udp,real-time,interrupt,qnx,C++,Udp,Real Time,Interrupt,Qnx,我有一个源,它以819.2赫兹(~1.2毫秒)的速率向我的QNX中微子机器发送UDP数据包。我希望以尽可能少的延迟和抖动接收和处理这些消息 我的第一个代码基本上是: SetupUDPSocket(); while (true) { recv(socket, buffer, BufferSize, MSG_WAITALL); // blocks until whole packet is received processPacket(buffer); } 问题是recv()仅在

我有一个源,它以819.2赫兹(~1.2毫秒)的速率向我的QNX中微子机器发送UDP数据包。我希望以尽可能少的延迟和抖动接收和处理这些消息

我的第一个代码基本上是:

SetupUDPSocket(); 
while (true) {
    recv(socket, buffer, BufferSize, MSG_WAITALL); // blocks until whole packet is received
    processPacket(buffer);
}
问题是recv()仅在系统的每个计时器滴答声时检查是否有新数据包可用。计时器的滴答声通常为1ms。所以,如果我使用这个,我会得到一个巨大的抖动,因为我每1ms或每2ms处理一个数据包。我可以重置计时器刻度的大小,但这会影响整个系统(以及其他进程的其他计时器等)。我仍然会有抖动,因为我肯定不会完全匹配819.2赫兹

因此,我尝试使用网卡的中断线(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;
} 
和“nicinfo”输出:

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 
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

谢谢你的阅读

您的UDP数据包有多大?如果数据包大小较小,则通过将更多数据打包到单个数据包中并降低传输速率,您将获得更高的效率。

我怀疑中断服务路由(ISR)没有屏蔽中断。也许它是为边缘敏感而设计的,并且中断是级别敏感的。

我不太清楚为什么“问题是recv()只在系统的每个计时器滴答声检查是否有新的数据包可用。计时器滴答声通常为1ms”这句话对于抢占式操作系统是正确的。系统配置中一定有问题,或者网络协议栈实现存在一些问题

几年前,当我为Yahoo BB Japan开发IPTV机顶盒项目时,我遇到了RTP接收问题。问题不在于延迟或抖动,而是在STB中添加一些NDS算法后的整体系统性能。我们使用的是vxWorks,vxWorks支持以太网钩子接口,驱动程序每次接收到以太网数据包时都会调用该接口


我在其中挂接了一个API,并直接从以太网数据包解析具有指定端口的UDP。当然,我们有一些假设,没有碎片,这是由网络设置的性能问题保证的。也许您也可以检查一下,看看是否可以在QNX以太网驱动程序中获得相同的钩子。至少你知道抖动是否来自驱动程序

对不起,我来晚了一点,但我遇到了你的问题,发现这与我遇到的情况类似。您可以尝试使用信号进行软件中断,而不是硬件中断。QNX在这里有一些文档:。当时我正在使用CentOS,但理论是一样的。根据需要,您可以使用ioctl()为给定文件描述符的SIGIO信号设置接收组…在您的示例中是UDP套接字。当套接字具有准备读取的数据时,会向ioctl()指示的进程发送一个SIGIO信号。使用sigaction()告诉操作系统要使用什么信号处理函数。在您的情况下,信号处理程序可以从套接字读取数据并将其存储在缓冲区中进行处理。使用pause()暂停进程,直到它处理SIGIO信号。当信号处理程序返回时,进程将唤醒,您可以处理缓冲区中的数据。
这将允许您在数据进入时处理数据,而无需处理计时器或硬件中断。需要注意的一点是,您的系统处理这些信号的速度与UDP通信的速度一样快

“问题是recv()只在系统的每个计时器点检查是否有新的可用数据包”-为什么会这样做?我不知道QNX,-网络驱动程序工作不正常吗?中断驱动程序应该设置一个事件/信号量并通过操作系统退出,这样它就可以“立即”设置recv()线程就绪。应该不需要任何“等待计时器滴答声”——这是毫无希望的——也可以使用合作轮询循环:(Martin提到的实现细节可能因驱动程序,甚至卡的具体型号而有所不同,但您也没有列出。@MartinJames和Ben Voigt:对不起,我不知道我的问题可能与驱动程序有关。'nicinfo'表示“英特尔82544千兆(铜)以太网控制器”和“pci-vvv”输出“供应商ID=8086h,英特尔公司设备ID=107ch,82541PI千兆以太网控制器”是否有用(甚至可能)要在源位置为数据包添加时间戳,以便您不需要依赖数据包接收的时间安排?如果您使用
MSG_PEEK
而不是
MSG_WAITALL
进行繁忙等待,会怎么样?中断边缘敏感还是级别敏感?