RTI_DDS自定义插件开发 4 接收方

本节介绍用于接收消息的Transport Plugin接口。

RecvResource概念
    用于发送的SendResource的补充是用于接收的RecvResource。 RecvResource必须链接(关联)到一个特定的端口(也可能是多播地址),以接收通过传输发送给应用程序的消息。 与SendResources类似,传输插件可以共享多个端口的RecvResource。 对于NDDS希望接收消息的新端口,NDDS将反复调用share_recvresource_rrEA()来共享现有的RecvResource,或者,如果Transport Plugin不能共享,则最后请调用create_recvresource_rrEA() 。
    请注意 ,由于传输接收到的消息的目标地址将是Transport Plugin管理的接口之一的地址(请参阅使用多接口接收 ),因此只需定义一个端口即可定义RecvResource。 端口只是NDDS配置传输的一种方式,以便在消息到达插件后进一步路由消息。 所以,所有发送到同一端口的消息应该通过相同的RecvResource接收。 使用哪些特定的端口号以及为什么通过高于传输插件的NDDS层来确定。
    NDDS将创建单独的线程以在不同的RecvResources上接收。 因此,对不同RecvResources的receive_rEA()将由不同的线程完成。
    为了了解NDDS多久尝试为一个Transport Plugin的特定实例共享或创建一个RecvResource的想法,请考虑一个简单的NDDS应用程序和一个参与者。
    当创建参与者时,NDDS将尝试首先共享,然后在共享之后创建一个RecvResource,用于每个Transport Plugin实例的单播元数据流量。 如果使用配置,NDDS也将尝试共享/创建RecvResources以实现多播元数据流量。
    然后,如果应用程序具有数据读取器,NDDS将共享/创建RecvResource以在默认端口上接收消息。 默认情况下,将只为所有DataReader创建一个。 但是,用户可以将DataReader配置为在默认使用以外的端口上接收消息。 用户还可以配置DataReader以使用多播地址接收消息。 当这些数据读取器被创建时,NDDS将尝试为不同的端口和/或多播地址共享/创建RecvResources。
    Transport-Plugin实现决定是否需要为不同的端口/多播地址创建不同的RecvResource,或者是否可以共享现有的RecvResource。 再次请注意,对于创建的每个RecvResource,NDDS将使用不同的线程从RecvResource接收消息。
    如果应用程序具有DataWriter,则NDDS还将创建默认的RecvResource以接收与可靠的DataWriter相关的消息。 此RecvResource用于接收来自相应DataReader的元数据(如来自支持可靠消息传递的确认)。 默认情况下,为所有DataWriters创建一个RecvResource。 但是,像DataReaders一样,用户可以配置DataWriter以在不同的端口上使用它来获取其元数据。 对于那些DataWriters,当它们被创建时,NDDS将尝试共享/创建指定端口的RecvResource。
    在DataWriter和DataReader中使用默认配置和多播的最简单应用程序未被使用时,NDDS将尝试共享/创建3个RecvResources(一个用于发现元数据流,一个用于DataWriter元数据流,另一个用于DataReader)。 如果创建的DataReader和DataWriters配置为接收除默认单播端口和/或使用多播之外的任何消息,则NDDS将尝试共享/创建更多RecvResources。
    要求创建RecvResource时,Transport Plugin应该做什么?
    实质上,传输插件必须创建它所需的所有资源,并初始化底层传输硬件和软件,以开始接收并存储由另一个传输插件实例发送的消息(排队)。 用于收集这些消息的Transport-Plugin特定资源的句柄作为RecvResource传递回NDDS。 当NDDS的上层准备从RecvResource中检索收到的消息时,NDDS将调用receive_rEA() 。

    通常,RecvResource表示传入消息的FIFO队列,这些消息被发送到与RecvResource关联的端口。 队列的大小取决于实现。 这可以是创建时传输插件集的一个属性,甚至可以为更复杂的实现动态调整。

接收多个接口
    如果一个传输器管理多个接口,那么当NDDS创建一个RecvResource时,它期望传输插件准备接收发往所有接口给定端口的消息。

    例如,如果将串行传输插件配置为管理多个串行端口并因此具有多个接口,那么当为串行传输插件创建RecvResource时,该插件应该做它需要做的以开始接收来自所有串口。

阻止接收
    NDDS核心将调用receive_rEA()来收集由RecvResource存储的消息。 请注意,如果RecvResource已共享,则RecvResource可能会存储针对不同目的地收到的消息。
    当receive_rEA() ,它应该从RecvResource的队列中返回一条消息。 如果在队列中没有等待消息,则receive_rEA()必须阻止调用者线程,直到传输接收到消息。
    如果消息比NDDS核心呼叫receive_rEA()更快地收到RecvResource以收集消息,则Transport Plugin可能会用尽内存(队列中的空间)来存储传入的消息。 在这种情况下,传输插件被允许悄悄丢弃消息。 如果NDDS确定它需要(例如,支持可靠的消息传递),它本身将重新发送消息。
    传输插件必须实现unblock_receive_rrEA()函数,作为解除阻塞调用receive_rEA()函数的线程的一种方式,即使没有收到消息。 主要用于关闭时,NDDS内核中的另一个线程将调用unblock_receive_rrEA()函数来唤醒接收线程。
    receive_rEA()函数应该知道它被unblock_receive_rrEA()唤醒并返回指示没有收到消息(0字节)。
    请注意 ,如果unblock_receive_rrEA()并且receive_rEA()没有当前阻塞的线程,则下一次对receive_rEA()必须返回,表明没有收到消息 - 即使队列中收到消息。 这意味着Transport Plugin必须记住调用了unblock_receive_rrEA() ,但是没有线程被调用唤醒。当接收线程最终调用时receive_rEA(),先前的调用unblock_receive_rrEA()将receive_rEA()立即返回,表示没有收到消息(即使接收队列中有消息)。
    如果线程试图关闭NDDS调用unblock_receive_rrEA(),但接收线程正忙于处理接收到的消息,则需要此“内存”(如果信号量用于阻止接收线程,则可使用计数信号量来实现此功能)实际上并未被阻止receive_rEA()

接收到连续缓冲区
    与传输插件的发送端的收集 - 发送设计相反,接收端必须总是将接收到的消息存储到一个连续的存储区域(缓冲区)中。
    一个传输插件实现可能会发送一条消息,但它需要,例如,作为一个单一的数据包,多个数据包,或者一个包含标题和分隔符的位流。接收端应该收集收到的字节,直到收到完整的消息并存储在连续的存储单元中。只有这样,消息才能存储在队列中供以后通过receive_rEA()呼叫检索。
    如果传输插件确定消息的一部分丢失或已被破坏,则应丢弃整个消息。不应将不完整或部分消息传递给NDDS。
可选的“Loaned-Buffer”机制
    在receive_rEA()调用中,Transport-Plugin实现可以通过将消息复制到作为参数传入的NDDS缓冲区,将接收到的消息返回给NDDS buffer_in。可选地,传输插件可以忽略buffer_in,而是通过返回一个指向消息(已经)存储的“内部”缓冲区的指针来传递接收到的消息。
    这种方法被称为“借用缓冲区”到NDDS核心。当NDDS核心处理完贷款缓冲区中的消息后,它将调用传输插件提供的函数plugin->return_loaned_buffer_rEA(),将借出的缓冲区返回给插件。在NDDS receive_rEA()再次调用相同的RecvResource 之前,一个借出的缓冲区总是会被返回。
    使用“借用缓冲”机制的主要原因是通过传输插件向NDDS核心提供高效的零拷贝接收实现。
    一些物理传输在设备驱动程序级别上已经有一个零拷贝接口。例如,在某些操作系统(如VxWorks)中,IP堆栈本身可以借用包含接收到的消息的单个缓冲区。在这种情况下,Transport Plugin应该能够将此缓冲区直接传递到NDDS核心,而不需要中间副本。这是“零拷贝”优化。
所以运输可以分为三类。
    没有零拷贝。在这种情况下,传输插件必须始终使用NDDS提供的缓冲区来返回消息。不会发生传输内部缓冲区的借用。插件实现应该将用于返回一个借用缓冲区的函数指针设置为NULL,NDDS_Transport_PluginImpl :: return_loaned_buffer_rEA,表示在NDDS处理接收到的消息之后不需要做任何事情。
    总是可以零复制。当receive_rEA()调用检索收到的消息时,一些传输将始终将传输内部缓冲区租借给NDDS内核。这些缓冲区通常是物理传输本身用于存储接收到的消息的缓冲区。所以这类传输可以提供处理收到的消息的最有效的方式。如果一个传输插件承诺总是借用一个缓冲区,NDDS内核的内存效率会更高,并且不会分配一个buffer_in插件永远不会用来复制收到的消息的缓冲区()。这样的传输应该在NDDS_Transport_Property_t :: properties_bitmap,NDDS_TRANSPORT_PROPERTY_BIT_BUFFER_ALWAYS_LOANED中设置一点,让NDDS内核知道它会一直返回借用缓冲区中的消息。
    有时可以零复制。一些传输可以对某些消息使用零复制方式,但对其他传输方式则不行。例如,支持零拷贝的IP堆栈可能会在非连续缓冲区中存储传入消息。没有首先将消息复制到单个连续缓冲区(可能在NDDS提供的缓冲区中),传输插件将无法将此消息发送给NDDS receive_rEA()。在这种情况下,Transport Plugin不应该设置NDDS_Transport_Property_t :: properties_bitmap的NDDS_TRANSPORT_PROPERTY_BIT_BUFFER_ALWAYS_LOANED位。相反,它将选择使用NDDS提供的缓冲区,或根据传输接收消息的方式将消息返回到借用缓冲区中。
NDDS核心本身将以相当透明的方式处理这三种情况。除非为特定传输插件设置了NDDS_TRANSPORT_PROPERTY_BIT_BUFFER_ALWAYS_LOANED位,receive_rEA()否则将始终使用足够大的缓冲区来调用传输插件配置为接收的最大消息。

    如果传输插件实现安装了NDDS_Transport_PluginImpl :: return_loaned_buffer_rEA函数,那么如果传输已经在该receive_rEA()函数中为NDDS提供了一个缓冲区,return_loaned_buffer_rEA()那么在完成消息处理后NDDS将会调用。
    如果在消息没有 贷款,并且return_loaned_buffer_rEA()应该不叫,然后运输插件必须设置的值loaned_buffer_param NDDS_Transport_Message_t ::至-1。NDDS将解释任何其他值作为消息中的缓冲区被借出并return_loaned_buffer_rEA()用该消息呼叫的指示。



猜你喜欢

转载自blog.csdn.net/xinqingwuji/article/details/79933638