当前位置: 首页 > news >正文

RTPS通信使用的socket和端口

RTPS通信使用的socket和端口

概述

​ 在FastRTPS中,无论SenderResource还是,ReceiverResource,其内部会依赖NetworkFactory创建socket,每个socket都需要绑定socket才能正常使用。

​ 一般来说,一个RTPSParticipant中创建的RTPSReader/RTPSWriter都是共用一组socket资源的,而这些socket的端口的值一般是RTPSParticipant的domainid和participantid相关的。

​ 上层应用可以指定创建的RTPSParticipant用于元数据和业务数据通信的单播地址/组播地址,但是无法指定通信的端口,端口是RTPS中根据规则进行计算分配的。

​ 下面主要是梳理一下一个RTPSParticipant会创建哪些socket,每一类socket绑定的端口规则是怎样的。

创建的socket

​ 通过阅读RTPSReader,RTPSWriter,StatelessWriter,StatelessReader,StatefulWriter以及StatefulReader的代码可以发现,这些endpoint类是只负责处理数据,管理匹配的对端endpoint,而发送和接收数据都是依赖内部的history对象的。history中的数据则是依赖了下层的ReceiverResource和SenderResource,而ReceiverResource和SenderResource是依赖了更下层Transport中的各种ChannelResource来进行网络数据通信的,每个ChannelResource中包含了用于地层数据通信的socket对象

发送

​ 发送的Socket在SenderResource中创建,有如下几个创建的时机点

​ 1. 创建RTPSParticipant设置qos的时候

DomainParticipantImpl::set_qosRTPSParticipant::update_attributesRTPSParticipantImpl::update_attributescreateSenderResources(元数据组播地址)createSenderResources(元数据单播地址)createSenderResources(业务数据单播地址)NetworkFactory::build_send_resourcesUDPTransportInterface::OpenOutputChannelUDPTransportInterface::OpenAndBindUnicastOutputSocketUDPTransportInterface::createUDPSocket

​ 2. StatelessWriter匹配到对端Reader

StatelessWriter::matched_reader_addStatelessWriter::update_reader_infoRTPSParticipantImpl::createSenderResources

​ 3. StatefulWriter匹配到对端Reader

StatefulWriter::matched_reader_addStatefulWriter::update_reader_infoRTPSParticipantImpl::createSenderResources

​ 4. StatefulReader匹配到对端Writer(需要创建SenderResource用于发送ACKNACK消息)

StatefulReader::matched_writer_addRTPSParticipantImpl::createSenderResources

接收

​ 接收的Socket在ReceiverResource中创建,

元数据组播地址绑定的端口

​ https://gitee.com/zzl0109/Fast-DDS/blob/master/include/fastdds/rtps/common/PortParameters.h

    inline uint32_t getMulticastPort(uint32_t domainId) const{uint32_t port = portBase + domainIDGain * domainId + offsetd0;...return port;}

元数据单播地址绑定的端口

​ https://gitee.com/zzl0109/Fast-DDS/blob/master/include/fastdds/rtps/common/PortParameters.h

inline uint32_t getUnicastPort(uint32_t domainId,uint32_t RTPSParticipantID) const{uint32_t port = portBase + domainIDGain * domainId + offsetd1   + participantIDGain * RTPSParticipantID;...return port;}

业务数据单播地址绑定端口

​ https://gitee.com/zzl0109/Fast-DDS/blob/master/src/cpp/rtps/participant/RTPSParticipantImpl.cpp

...
RTPSParticipantImpl::RTPSParticipantImpl(...// 上层应用未指定单播和组播地址if (m_att.defaultUnicastLocatorList.empty() && m_att.defaultMulticastLocatorList.empty()){get_default_unicast_locators();internal_default_locators_ = true;EPROSIMA_LOG_INFO(RTPS_PARTICIPANT,m_att.getName() << " Created with NO default Unicast Locator List, adding Locators:"<< m_att.defaultUnicastLocatorList);}else{// Locator with port 0, calculate port.  指定了地址,通过计算分配端口std::for_each(m_att.defaultUnicastLocatorList.begin(), m_att.defaultUnicastLocatorList.end(),[&](Locator_t& loc){   // 端口通过calculate_well_known_port计算m_network_Factory.fill_default_locator_port(domain_id_, loc, m_att, false);});m_network_Factory.NormalizeLocators(m_att.defaultUnicastLocatorList);std::for_each(m_att.defaultMulticastLocatorList.begin(), m_att.defaultMulticastLocatorList.end(),[&](Locator_t& loc){   // 端口通过calculate_well_known_port计算m_network_Factory.fill_default_locator_port(domain_id_, loc, m_att, true);});}...
}...void RTPSParticipantImpl::get_default_unicast_locators()
{m_network_Factory.getDefaultUnicastLocators(domain_id_, m_att.defaultUnicastLocatorList, m_att);m_network_Factory.NormalizeLocators(m_att.defaultUnicastLocatorList);
}...

​ https://gitee.com/zzl0109/Fast-DDS/blob/master/src/cpp/rtps/network/NetworkFactory.cpp

bool NetworkFactory::getDefaultUnicastLocators(uint32_t domain_id,LocatorList_t& locators,const RTPSParticipantAttributes& m_att) const
{bool result = false;for (auto& transport : mRegisteredTransports){result |= transport->getDefaultUnicastLocators(locators, calculate_well_known_port(domain_id, m_att, false));}return result;
}bool NetworkFactory::fill_default_locator_port(uint32_t domain_id,Locator_t& locator,const RTPSParticipantAttributes& m_att,bool is_multicast) const
{bool result = false;for (auto& transport : mRegisteredTransports){if (transport->IsLocatorSupported(locator)){   // 端口通过calculate_well_known_port计算result |= transport->fillUnicastLocator(locator, calculate_well_known_port(domain_id, m_att, is_multicast));}}return result;
}uint16_t NetworkFactory::calculate_well_known_port(uint32_t domain_id,const RTPSParticipantAttributes& att,bool is_multicast) const
{uint32_t port = att.port.portBase +att.port.domainIDGain * domain_id +(is_multicast ?att.port.offsetd2 :att.port.offsetd3 + att.port.participantIDGain * att.participantID);if (port > 65535){...  // error logexit(EXIT_FAILURE);}return static_cast<uint16_t>(port);
}

业务数据组播地址绑定端口

业务数据的接收socket,其绑定的端口逻辑如下:

发送业务数据使用的端口

发送数据时需要通过SenderResource 
bool NetworkFactory::build_send_resources(
{...for (auto& transport : mRegisteredTransports){returned_value |= transport->OpenOutputChannel(sender_resource_list, locator);}...
}bool UDPTransportInterface::OpenOutputChannel(SendResourceList& sender_resource_list,  // 返回创建的SenderResource列表const Locator& locator)
{..uint16_t port = configuration()->m_output_udp_socket;  //获取通信端口,默认位0if (is_interface_whitelist_empty()) // 没有设置网卡白名单的情况else {// 没有设置网卡白名单的情况,根据locator对应地址找到合适的网卡集合get_unknown_network_interfaces(sender_resource_list, locNames, true);for (const auto& infoIP : locNames) {// 创建socket(绑定infoIP对应的网卡IP),port=0则绑定随机端口eProsimaUDPSocket unicastSocket =                        OpenAndBindUnicastOutputSocket(generate_endpoint(infoIP.name, port), port);// 设置带外数据通信属性SetSocketOutboundInterface(unicastSocket, infoIP.name);if (first_time_open_output_channel_){   // 如果是首次创建该Transport下的senderreosurce,则设置multicast::enable_loopback,允许组播数据回送127.0.0.1getSocketPtr(unicastSocket)->set_option(ip::multicast::enable_loopback(true));first_time_open_output_channel_ = false;}// 使用前面创建的socket新建SenderResource并且返回给调用方sender_resource_list.emplace_back(static_cast<SenderResource*>(new UDPSenderResource(*this, unicastSocket, false, true)));}}...
}

http://www.mrgr.cn/news/77764.html

相关文章:

  • 股指期货的套保策略如何精准选择和规避风险?
  • 【React】React Router:深入理解前端路由的工作原理
  • MATLAB GUI设计(基础)
  • 开源宝藏:Smart-Admin 重复提交防护的 AOP 切面实现详解
  • 【人工智能】深入理解图神经网络(GNN):用Python实现社交网络节点分类与分子结构分析
  • vue3+vite项目如何使用xlsx结合xlsx-style-vite导出EXCEL
  • Linux各种并发服务器优缺点
  • 12 —— Webpack中向前端注入环境变量
  • 2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略(详细解题思路)
  • IDEA算法的详细介绍及Python实现
  • 2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略 (python 代码+matlab代码)
  • 乐理的学习(和弦)
  • c++11的动态类型
  • 二叉树相关OJ题练习
  • 2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略 完整参考论文(1)
  • DrissionPage爬虫工具教程
  • Node基本使用
  • java学习记录12
  • <OS 有关> ubuntu 24 不同版本介绍 安装 Vmware tools
  • 项目实践----springboot中设计基于Redisson的分布式锁注解
  • 实用功能,觊觎(Edge)浏览器的内置截(长)图功能
  • oracle排查长时间没提交的事务造成的阻塞案例
  • Spring循环依赖如何解决的?
  • Pytorch使用手册-Datasets DataLoaders(专题三)
  • 学习日志015--python单链表
  • Mybatis,Druid,lombok