fastdds:传输层端口号计算规则

fastdds:传输层端口号计算规则
当使用UDP或者SHM作为传输层时我们经常看到7400、7410、7411、7412这些端口号。那么这些端口号是怎么计算出来的又有什么用呢如下图所示使用fastdds中的例子delivery_mechanisms指定传输层为UDPv4启动了两个publisher。启动的第一个publisher使用了端口号7400、7410、7411第二个publisher使用了端口号7400、7412、7413。dds流量有两类发现流量和用户流量。发现流量(PDP/EDP)用于particiapant以及data writer/data reader之间的发现用户流量用于收发用户数据。发现流量需要用到多播和单播。发现流量是用户流量的基础只有相互发现的data writer/data reader之间才能够进行数据传输。发现流量作为dds工作的基础和发起点本身没有前置条件所以在同一个domain内发现流量多播端口号需要时众所周知的。发现流量多播端口PB DG *domainId d0多播端口只受domaiId影响所以在同一个domain内的所有participant均使用相同的多播端口这也说明只有在同一个domain内的participant才能相互发现。默认情况下组播地址是239.255.0.1不同的domain变的只有端口多播地址不会变。每一个participant创建之后都要通过多播的方式向多播组内发布自己的信息。发现过程除了使用多播还会使用单播。假如一个domain内有3个participant分别为A、B、C。假如A发布的多播消息那么B和C都会收到如果B和A之间有相同topic的writer和reader也就是说B和A是可以通信的那么B就会向A发送单播消息进行后续的协商后边的协商过程均通过单播来实现。这里跟tcp建立连接的过程是有些相似的tcp建立连接时客户端需要向服务端发起连接tcp服务端接收连接请求的是监听套接字这个套接字类似于多播流量当监听套接字收到连接请求后会在创建一个新的套接字与客户端形成连接后边的用户流量都通过新的套接字来进行。发现流量单播端口PB DG *domainId d1 PG *participantId如果domainId是0participantId也是0那么发现流量的多播端口是7400单播端口是7410。在函数RTPSParticipantImpl::createReceiverResources中首先使用7410端口进行绑定如果失败那么会进行重试重试就是重新选择一个新的端口来使用。在函数RTPSParticipantImpl::applyLocatorAdaptRule中选择新的端口选择新的端口的算法就是在端口的基础上加上delta默认情况下delta是2。单播端口在多播报文中会携带。单播端口也不完全由domainId和participantId来决定。participantId的分配如下代码所示同一个进程的同一个domain内participantId都是从0开始的也就是说participantId并不是domain内唯一的而是domain和进程内唯一的。如果我们使用udp传输层但是publisher和subscriber在同一台机器上的两个进程中那么两者的participantId都是0那么两个进程都要使用单播端口7410吗这样显然是不对的。uint32_t RTPSDomainImpl::getNewId(){// Get the smallest available participant ID.// Settings like maxInitialPeersRange control how many participants a peer// will look for on this host.// Choosing the smallest value ensures peers using unicast discovery will// find this participant as long as the total number of participants has// not exceeded the number of peers they will look for.uint32_t i 0;while (m_RTPSParticipantIDs[i].reserved || m_RTPSParticipantIDs[i].used){i;}m_RTPSParticipantIDs[i].reserved true;return i;}bool RTPSParticipantImpl::createReceiverResources(LocatorList_t Locator_list,bool ApplyMutation,bool RegisterReceiver,bool log_when_creation_fails){...for (auto it_loc input_list.begin(); it_loc ! input_list.end(); it_loc){Locator_t loc *it_loc;bool ret m_network_Factory.BuildReceiverResources(loc, newItemsBuffer, max_receiver_buffer_size);if (!ret ApplyMutation){uint32_t tries 0;while (!ret (tries m_att.builtin.mutation_tries)){tries;applyLocatorAdaptRule(loc);ret m_network_Factory.BuildReceiverResources(loc, newItemsBuffer, max_receiver_buffer_size);}}...}Locator_t RTPSParticipantImpl::applyLocatorAdaptRule(Locator_t loc){// This is a completely made up rule// It is transport responsibility to interpret this new port.uint16_t delta m_att.port.participantIDGain;if (metatraffic_unicast_port_ loc.port){metatraffic_unicast_port_ delta;//这就是各种gain的用途是在判断端口号已经被占用的时候进行步进选择的}loc.port delta;return loc;}一般情况下用户的流量使用单播来进行计算公式如下。同样的如果单播端口已经被占用那么就会进行重试重试的算法是在上一个端口的基础上加2。用户流量单播端口PB DG *domainId d3 PG *participantId这样我们就能知道下图中的端口分别是做什么用的了7400两个进程的都会使用的组播端口用于发现流量7410:5013进程发现流量的单播端口7411:5013进程用户流量的单播端口7412:5025进程发现流量的单播端口7413:5025进程用户流量的单播端口共享内存借用UDP中端口的概念还是使用例子delivery_mechanisms指定传输层是SHM在/dev/shm下可以看到如下文件其中7400、7410、7411、7412、7413也是用来标记通信的端口。共享内存和UDP都是dds中标准的传输层都是带port的传输层。