RTI_DDS自定义插件开发 3 发送方

本节介绍发送消息的传输插件的接口。

收集发送
    当NDDS通过传输插件发送消息时,它将为传输插件提供一系列缓冲区。 传输插件负责将此缓冲区数组连接成传递的单个消息。 数组中所有缓冲区的连接是NDDS希望在传输的另一端收到的实际消息。
    传输插件的接收端应仅向NDDS提供完整消息,而不是单独呈现构成消息的每个缓冲区。 因此,在发送端,传输插件可以一次将缓冲区数组发送到单个缓冲区,在接收端,它应该等到所有缓冲区都收到完整的消息发送到NDDS之前。
这种方法在NDDS内核和Transport Plugin之间提供了一个处理时间高效的接口。 它避免了NDDS需要额外的副本将消息的子部分合并到一个连续的缓冲区中进行发送。 此方法还允许传输插件利用物理传输,这些传输也提供“收集 - 发送”API,例如IP套接字。

    在底层传输机制只能发送单个缓冲区的情况下,传输插件的实现或者需要在发送之前将缓冲区阵列中的缓冲区复制到一个连续的缓冲区中,或者放置一些逻辑来检测何时所有具有缓冲区的缓冲区已被单独寄出。

只有同步发送
    Transport-Plugin API的“发送”调用应该是同步的。 也就是说,当“发送”调用返回时,NDDS核心可以假设消息已经由插件发送,并且传递给“发送”调用的缓冲区数组可以自由地重新使用。
请注意,在多个实时操作系统上进行的性能测试显示,在发送端使用异步零拷贝方法没有显着的性能改进。 一般来说,利用异步发送对于NDDS内核的设计来说要复杂得多,并且目前NDDS不支持。
SendResource概念
    在NDDS可以向目的地发送消息之前,NDDS必须确定哪个传输插件能够发送到目的地(IPv6地址+端口组合)。 它通过使用Transport Plugin“预注册”目的地来实现。 换句话说,NDDS核心将调用传输插件( create_sendresource_srEA() )中的函数来创建NDDS尝试向目标发送消息之前传输需要发送到目标的任何资源。
    传输插件应该确定它是否能够发送到目的地(地址/端口)。 如果可以,那么插件应该创建或以其他方式初始化所需的任何底层传输机制,并将这些结果的句柄作为“SendResource”返回。 当NDDS稍后尝试向该目的地发送消息时,NDDS将返回相同的句柄到传输插件。
    对于某些类型的传输,插件可能不需要做任何不同的事情发送到不同的目的地。 在这种情况下,插件可能能够在多个目的地共享相同的SendResource。 因此,每当NDDS找到一个Transport Plugin的新目的地时,它将遍历一个Transport Plugin的现有SendResources,并通过调用create_sendresource_srEA()来调用share_sendresource_srEA()尝试共享一个SendResource,然后创建一个新的SendResource。
    NDDS发现传输插件的新目的地时的一个示例是NDDS检测到在本地DDS DataWriter的远程应用程序中创建了新的DDS DataReader。
    当NDDS确定它不需要通过特定传输插件发送到特定目标时,例如,如果DataReader在远程应用程序中被销毁,则NDDS将通知传输插件目标不再被任何呼叫使用destroy_sendresource_srEA() unshare_sendresource_srEA()或destroy_sendresource_srEA()与发送源链接到目标。 究竟调用哪个函数是由SendResource是否在多个目的地共享。
   什么破坏或取消共享SendResource意味着特定的Transport-Plugin实现完全取决于实现。 它可以是关闭套接字并释放相关资源而不做任何事情的任何东西。
   为了了解NDDS多久尝试为一个Transport Plugin的特定实例共享或创建一个SendResource的想法,请考虑一个简单的NDDS应用程序和一个参与者(下面的讨论假定您熟悉DDS概念并了解NDDS应用程序的一些知识发现工作并配置)。
    然后,对于对等定位器列表中的所有对等项,其地址可由传输器提供服务(必须与传输插件具有相同的网络地址,请参阅传输插件中的寻址 ),NDDS将尝试共享/创建SendResource(因为它会尝试发送消息到该对等体)。
    另外,对于发现的任何对等点(实际上是活动的并且已经交换了消息),NDDS将从对等点接收到应用程序应发送RTPS元数据包的接口/端口列表。 因此,对于Transport Plugin可以访问的任何远程对等接口,NDDS将尝试共享/创建该插件的SendResource。
    然后,在发现完成后,当NDDS发现与本地DataWriters匹配的远程DataReader时,它将收到应该用于将数据发送到远程DataReader的接口/端口组合列表。 同样,对于可由Transport Plugin提供服务的任何接口,NDDS将尝试共享/创建该插件的SendResource。
    因此,在最简单的应用程序中,DataWriter在另一个应用程序中具有匹配的DataReader,假设两个应用程序只有一个管理单个接口的传输插件,NDDS将尝试共享/创建2个SendResource; 一个用于元数据流量,另一个用于用户数据流量。 如果传输插件可以共享相同的SendResource以实现元数据流量和用户数据流量,则实际创建的SendResources数量可能只有1个。

    NDDS会要求Transport Plugin共享/创建更多的SendResource,因为它发现更多的对等应用程序,因为存在更多匹配的DataWriter / DataReader对,或者如果最终用户将应用程序配置为使用多播地址或指定DataReaders的端口以接收除默认端口。

    NDDS只会要求传输插件为新的唯一地址/端口组合共享/创建新的SendResource,以便传输插件实现永远不会被要求共享或创建已经共享或创建的地址/端口的SendResource一个SendResource。

发送多个接口
    当NDDS调用send() ,它将尝试发送消息到特定的目标(地址/端口)。 对于管理多个接口的传输插件(参见网络接口 ),可能会出现应该使用哪个接口的问题。 除非目标是多播消息,否则插件通常应该只选择一个接口来发送消息。
    例如,IP插件发送的UDP数据包通常会被操作系统的IP堆栈路由,因此它只能从多NIC系统中的单个接口发送出去。 通常,路由表确定哪个接口用于哪个目的地址。
    因此,虽然每个传输插件实现可能有不同的方式来处理多个接口(其中的细节可由最终用户配置),但通常具有单播目标的消息通过单个接口发送。 但是,实现可能选择通过多个接口冗余发送单播消息。 另外,由于具有组播地址的消息应该被监听组播地址的所有远程接口接收,因此传输插件应该通过支持组播的所有接口发送组播消息。
    虽然NDDS内核旨在正确处理重复消息(如果通过多个接口或甚至不同传输插件接收到相同的消息,则会发生这种情况),但实现者应该知道额外资源(CPU)将被消耗处理重复的消息。 另外,根据时间的不同,由于重复的消息,NDDS可能会不必要地产生(并处理)额外的元数据流量。
在接收器初始化之前发送面向连接的传输
    在构建面向连接的传输层之上建立发布 - 订阅网络机制时,存在鸡和蛋的问题,这种机制本质上是无连接的。 对于一个应用程序将数据发布到另一个应用程序,它需要知道其他应用程序已订阅了其数据。 但首先,该订阅的知识必须由订阅应用程序发送到发布应用程序。 哪个应用程序首先应该连接到另一个? 发布应用程序或订阅应用程序? 等等,是不是允许NDDS应用程序既是发布者又是订阅者?
    对于无连接传输而言,这不是什么大问题。 无需先建立连接,即可发送信息。 因此,即使没有其他应用程序准备好接收消息, create_sendresource_srEA()和send()调用也可以成功。 因此,在发送信息之前不需要建立连接。 如果接收应用程序启动,则它将接收数据。 如果它没有启动或准备就绪,则数据丢失,并且将由发送应用程序重新发送信息。
    在面向连接的传输中,通常在连接建立之前无法发送。 在Transport-Plugin API中,对于面向连接的传输,与特定目标的连接将通常在create_sendresource_srEA()调用中建立。 但是,由于应用程序是异步启动的,因此在第一个应用程序中调用create_sendresource_srEA()时,目标应用程序可能尚未启动或尚未完成连接。
    因此,当create_sendresource_srEA()返回时,发送方和接收方应用程序之间的连接可能尚未完全初始化(连接未建立)。 如果是这种情况,则面向连接的传输插件的create_sendresource_srEA()调用不得返回失败代码。 create_sendresource_srEA()只应该返回失败,如果插件确定没有可能的方式使用插件发送到给定的目标,而不仅仅是因为它不能建立连接。
    如果连接无法通过create_sendresource_srEA()建立,它仍然应该创建并返回一个SendResource给NDDS。 SendResource应该包含某种指示,表明它没有完全初始化,也就是说,与接收应用程序的连接还没有建立。
    然后,当NDDS需要使用SendResource发送消息到目的地时,它将通过Transport Plugin的send()命令中的部分初始化的SendResource。 对于面向连接的传输, send()调用必须检查与SendResource相关的连接是否完全建立。 如果没有, send()调用本身应该在发送之前尝试建立连接。 可能是到目的地的连接仍然无法建立(目标应用程序仍未准备好接受连接)。 在这种情况下, send()应该返回0以表示没有消息实际发送。
    对于所有的意图和目的,NDDS将把这种情况看作是由插件发送的消息以某种方式被丢弃。 NDDS将调用传输插件的send()函数来再次发送消息。 因此,Transport Plugin将定期有机会与目标应用程序建立连接。 假设接收应用程序最终启动,那么当send()被NDDS调用时,插件最终会建立连接并发送消息。

通过这种方式,NDDS可以使用面向连接的传输,而独立于传输的哪一边被首先初始化。

猜你喜欢

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