分布式系统-ORTE的原理与实现

在这里插入图片描述


```c
1.1	创建Domain: ORTEDomainAppCreate

ORTEDomainAppCreate
	-ORTEDomainCreate(domain, prop, events, ORTE_FALSE)
		sock_init_udp(&d->taskRecvUnicastMetatraffic.sock);
  		sock_init_udp(&d->taskRecvMulticastMetatraffic.sock);
  		sock_init_udp(&d->taskRecvUnicastUserdata.sock);
  		sock_init_udp(&d->taskRecvMulticastUserdata.sock);
  		sock_init_udp(&d->taskSend.sock);
 		appSelfParamChanged(d, ORTE_FALSE, ORTE_FALSE, ORTE_FALSE, ORTE_TRUE);  //通过d->writerApplicationSelf周期性的发送自身的信息
			-parameterUpdateCSChange(csChange, d->appParams, ORTE_TRUE);
	 		-CSTWriterAddCSChange(d, &d->writerApplicationSelf, csChange);
				-gavl_cust_for_each (CSTRemoteReader, cstWriter, cstRemoteReader) //遍历d->writerApplicationSelf 关联的RemoteReader, 最初manager没有remoteReader, 而每人上普通app都有一个默认的remotereader,就是manager,所以,每个普通的app启动后,均会向manager报告自己的app信息,app知道manager的端口:就是(7400 +d * 10)
	-ORTEDomainStart(d,                        /* domain */
		    ORTE_TRUE,                          /* recvUnicastMetarafficThread */
		    d->domainProp.multicast.enabled,    /* recvMulticastMetarafficThread */
		    ORTE_TRUE,                          /* recvUnicastUserdataThread */
		    d->domainProp.multicast.enabled,    /* recvMulticastUserdataThread */
		    ORTE_TRUE)
			-ORTEDomainRecvThreadStart(&d->taskRecvUnicastMetatraffic)
		      	      ORTEDomainRecvThreadStart(&d->taskRecvMulticastMetatraffic)
		      	      ORTEDomainRecvThreadStart(&d->taskRecvUnicastUserdata)
		     	      ORTEDomainRecvThreadStart(&d->taskRecvMulticastUserdata)
		      	      ORTEDomainSendThreadStart(&d->taskSend)
					-pthread_create(&(tp->thread), NULL, (void *)&ORTEAppRecvThread, (void *)tp);  //创建接收线程
					-pthread_create(&(tp->thread), NULL, (void *)&ORTEAppSendThread, (void *)tp);  //创建发送线程



每一个本地的 cstWrite,均有一个或多个 RemoteReader,通过CSTWriterAddRemoteReader这个接口给一个cstWrite增加一个RemoteReader,那么该 cstWriter在发送消息时,将会给 RemoteReader对发送一份,有几个RemoteReader,就会发送几份
同样,每一个本地的 cstReader,均有一个或多个 RemoteWrite,通过CSTReaderAddRemoteWriter这个接口给一个cstReader增加一个RemoteWriter,那么该 cstReader在接收消息时,将会为每个 RemoteWriter接收一次,有几个RemoteWriter,就会接收几次



1.2	发送线程:ORTEAppSendThread
ORTEAppSendThread
	-》htimerRoot_run_expired
		-》timer->func(d, timer->objectEntryAID, pact_time);


eventAdd
	-》fncNode->func = func;
	-htimerUnicastSendMetatraffic_update_root_timer(&d->objectEntry, objectEntryAID)


htimerUnicastSendMetatraffic_update_root_timer
	-》objectEntryAID->htimUnicast.sendMetatrafficNode.func = htimerUnicastSendMetatraffic_run_expired;
	-htimerRoot_add(objectEntry, &objectEntryAID->htimUnicast.sendMetatrafficNode)


htimerUnicastSendMetatraffic_run_expired
	-》ORTESendData
		-》port = appParams->metatrafficUnicastPort; //目的端口号:7400 + domain*10
		-》des.sin_port = htons((uint16_t)port);
		-sock_sendto(&d->taskSend.sock,     //将数据发到目的端口号
		      	d->taskSend.mb.cdrCodecDirect->buffer,
		      	d->taskSend.mb.cdrCodecDirect->wptr,
		      	&des,
		     	 sizeof(des))



1.3	接收线程:ORTEAppRecvThread
ORTEAppRecvThread
	-》RTPS_Codec_len = sock_recvfrom(
      		&tp->sock,                                 //socked handle
      		cdrCodec->buffer,                         //buffer
      		cdrCodec->buf_len,                        //max length of message
      		&des, sizeof(des))
	-recvfrom(sock->fd, buf, max_len, 0)  //读 socket
	-RTPSHeaderCheck(cdrCodec, RTPS_Codec_len, &mi)  //检测RTPS消息体的header是否合法
	-switch ((SubmessageId)sub_id) {
	    case VAR:
	             RTPSVar(d, cdrCodec, &mi, ntohl(des.sin_addr.s_addr));
	             break;
	    case ACK:
	             RTPSAck(d, cdrCodec, &mi, ntohl(des.sin_addr.s_addr));  //根据接收到不同消息,进行不同的响应
	    case HEARTBEAT:
	             RTPSHeartBeat(d, cdrCodec, &mi);  //处理接收到的心跳信息
	      break;

1.4	注册topic: ORTETypeRegisterAdd
ORTETypeRegisterAdd
	-ORTEType_find(&d->typeEntry, &typeName)
	-ORTEType_insert(&d->typeEntry, tn)


1.5	创建发布者并周期发布消息:ORTEPublicationCreate
在创建domain时,会创建很多内置的CSTWriter:
  CSTWriter              writerPublications;     //App
  CSTReader              readerPublications;     //App
  CSTWriter              writerSubscriptions;    //App
  CSTReader              readerSubscriptions;    //App

当发布一个普通的topic前,会调用该函数创建一个新的CSTWriter *cstWriter
ORTEPublicationCreate
	-eventAdd(d,
	       objectEntryOID->objectEntryAID,
	       &objectEntryOID->sendCallBackDelayTimer,
	       0,
	       "PublicationCallBackTimer",
	       PublicationCallBackTimer,  
	       &cstWriter->lock,
	       cstWriter,
	       &objectEntryOID->sendCallBackDelay);
	-CSTWriterInit(d, cstWriter, objectEntryOID, guid.oid, &cstWriterParams, &typeNode->typeRegister);  //创建一个cstwriter,用于传递要发布的业务数据
  	-CSTWriter_insert(&d->publications, cstWriter); //将这个 cstwriter加入到d->publications列表中
	-parameterUpdateCSChangeFromPublication(csChange, pp);    //生成一条消息,用于描述要通知其他订阅方的 topic 的元数据
		parameterPutString(ps, PID_TOPIC, pp->topic);
  		CSChangeAttributes_insert(csChange, ps);
		parameterPutString(ps, PID_TYPE_NAME, pp->typeName);
  		CSChangeAttributes_insert(csChange, ps);
	-CSTWriterAddCSChange(d, &d->writerPublications, csChange); //将此 topic 的元数据,加入到d->writerPublications的csChange中,然后,该通知消息会自动被发出去


PublicationCallBackTimer  //发送具体业务消息
	-ORTEPublicationSendLocked(cstWriter, NULL)
		-CDR_codec_init_static(&csChange->cdrCodec)  //初始化CDR序列化
		-RTPSHeaderCreate(&csChange->cdrCodec, cstWriter->domain->guid.hid, cstWriter->domain->guid.aid);
		-RTPSInfoTSCreate(&csChange->cdrCodec, getActualNtpTime());
    		-RTPSIssueCreateHeader(&csChange->cdrCodec, 16+max_size, OID_UNKNOWN, cstWriter->guid.oid, snNext);
		-》cstWriter->typeRegister->serialize(&csChange->cdrCodec, cstWriter->objectEntryOID->instance);  //序列化打包
		-CDR_buffer_puts(&csChange->cdrCodec, cstWriter->objectEntryOID->instance, max_size); //直接拷贝方式,2种方式二选一
		-CSTWriterAddCSChange(cstWriter->domain, cstWriter, csChange);  //加到这个 cstWriter对应的csChange中,注册:该数据是具体的消息内容,而不是元数据




当manager收到一个APP发来的publish meta data时,进入到这里:
RTPSVarApp
-case OID_WRITE_PUBL:
	-》cstReader = &d->readerPublications;
      	-》cstRemoteWriter = CSTRemoteWriter_find(cstReader, writerGUID);
	-parameterUpdatePublication(csChange, pp);
	-PublicationList_insert(&d->psEntry, objectEntryOID);
	-debug(46, 2) ("new publisher 0x%x-0x%x-0x%x accepted\n",GUID_PRINTF(csChange->guid));
	-NewPublisher(d, objectEntryOID);  //这个函数很重要,会进行发布者与订阅者之间的匹配工作
		-》pnode->subscriptionCallBack ((char *) pp->topic,
						     (char *) pp->typeName,
						     pnode->param);
		-if ((strcmp((const char *)pp->topic, (const char *)sp->topic) == 0) &&
		     (strcmp((const char *)pp->typeName, (const char *)sp->typeName) == 0) &&
		    (pp->typeChecksum == sp->typeChecksum))
		  -》 cstReader = CSTReader_find(&d->subscriptions, &o->guid)
		  -CSTRemoteWriter_find(cstReader, &op->guid)
		  -CSTReaderAddRemoteWriter(d, cstReader, op, op->oid);  // add Publisher to Subscriber
			-》CSTReaderQueryTimer
				-RTPSAckCreate(
    					&d->taskSend.mb.cdrCodec,
    					&cstRemoteWriter->sn,
    					cstRemoteWriter->cstReader->guid.oid,
    					cstRemoteWriter->guid.oid,
    					ORTE_FALSE)



1.6	创建订阅者:ORTESubscriptionCreate
ORTESubscriptionCreate
	-strcpy ((char *) sp->topic, topic);
   	-strcpy ((char *) sp->typeName, typeName);
	-》objectEntryOID = objectEntryAdd (d, &guid, (void *) sp);
   	-》objectEntryOID->privateCreated = ORTE_TRUE;
    	-》objectEntryOID->instance = instance;
   	-》objectEntryOID->recvCallBack = recvCallBack;
   	-》objectEntryOID->callBackParam = recvCallBackParam;
	-CSTReaderInit (d, cstReader, objectEntryOID, guid.oid, &cstReaderParams, &typeNode->typeRegister);
	-CSTReader_insert (&d->subscriptions, cstReader);  // d->subscriptions这棵树里面,记录了每个cstReader,每一个发布者都是一个cstReader
	-parameterUpdateCSChangeFromSubscription (csChange, sp);
	-CSTWriterAddCSChange (d, &d->writerSubscriptions, csChange);  //发送关于订阅的元消息
	-gavl_cust_for_each (CSTRemoteReader, cstWriter, cstRemoteReader)  //遍历所有远程的订阅者
    	{
		eventAdd (d,
			cstRemoteReader->sobject->objectEntryAID,
			&cstRemoteReader->delayResponceTimer,
			1,
			"CSTWriterSendTimer",
			CSTWriterSendTimer,  //周期性发送业务 消息
			&cstRemoteReader->cstWriter->lock, cstRemoteReader,
			NULL);
	}



1.7	业务消息收发过程
1.7.1	发布者发布消息:
ORTEPublicationSendLocked
	-RTPSHeaderCreate (&csChange->cdrCodec,
			    cstWriter->domain->guid.hid,
			    cstWriter->domain->guid.aid);
	-RTPSInfoTSCreate (&csChange->cdrCodec, getActualNtpTime ());
	-RTPSIssueCreateHeader (&csChange->cdrCodec, 16 + max_size,
				 OID_UNKNOWN, cstWriter->guid.oid, snNext);
	-》cstWriter->typeRegister->serialize (&csChange->cdrCodec,                                      //序列化
						    cstWriter->objectEntryOID->
						    instance);
	-CSTWriterAddCSChange (cstWriter->domain, cstWriter, csChange)
		-gavl_cust_for_each (CSTRemoteReader, cstWriter, cstRemoteReader)   //insert new cschange for each reader
    		   {
			eventAdd (d,
				cstRemoteReader->sobject->objectEntryAID,
				&cstRemoteReader->delayResponceTimer,
				1,
				"CSTWriterSendTimer",
				CSTWriterSendTimer,
				&cstRemoteReader->cstWriter->lock, cstRemoteReader,
				NULL);
     		    }
			-》CSTWriterSendTimer
				-gavl_cust_for_each (CSChangeForReader, cstRemoteReader, csChangeForReader)


1.7.2	订阅者接收消息:
RTPSIssue
	-gavl_cust_for_each (CSTReader, &d->subscriptions, cstReader)
	-》cstRemoteWriter = CSTRemoteWriter_find (cstReader, &writerGUID);
	-》CSTReaderProcCSChangesIssue
		-CSTReaderNewData (cstRemoteWriter, csChangeFromWriter)
			-》cstRemoteWriter->cstReader->typeRegister->deserialize (&csChange->cdrCodec, objectEntryOID->instance)       //反序列化
			-》objectEntryOID->recvCallBack (&info, objectEntryOID->instance, objectEntryOID->callBackParam)


1.8	关于端口号的分配:
对于 manager来说:
p = 7400 + d*10;
给d->taskRecvUnicastMetatraffic 指定端口: (7400 +d * 10) 

对于普通app来说:
给d->taskRecvUnicastUserdata.sock , d->taskRecvUnicastMetatraffic, d->taskSend.sock 指定端口0,表示由系统自动分配一个可用的端口


1.9	关于内置端点
1.9.1	Common:
d->writerApplicationSelf
d->readerManagers
d->readerApplications


1.9.2	manager:
d->writerApplications
d->writerManagers


1.9.3	normal app:
d->writerPublications   //通过它发送pub的元消息
d->writerSubscriptions //通过它发送sub的元消息
d->readerPublications
d->readerSubscriptions



1.9.4	内置的ID
#define OID_UNKNOWN              0x00000000
#define OID_APP                 	 0x000001C1
#define OID_WRITE_APPSELF        0x000008C2
#define OID_READ_APPSELF         0x000008C7
#define OID_WRITE_APP            0x000001C2
#define OID_READ_APP             0x000001C7           //收到 一个APP加入 的描述消息
#define OID_WRITE_MGR            0x000007C2
#define OID_READ_MGR             0x000007C7
#define OID_WRITE_PUBL           0x000003C2        
#define OID_READ_PUBL            0x000003C7           //收到发布topic 的描述消息
#define OID_WRITE_SUBS           0x000004C2
#define OID_READ_SUBS            0x000004C7           //收到订阅topic 的描述消息


 
1.10	RTPS消息
根据RTPS协议规范,RTPS Submessage中的INFO子消息可以分为以下几种类型:
INFO_TS:用于指示子消息的时间戳信息。它包含了一条时间戳,表示消息发送的时间。
INFO_SRC:用于指示消息发送者的身份信息。它包含了消息发送者的GUID(全局唯一标识符)和VendortID(供应商ID)。
INFO_REPLY_IP4:用于指示IPv4地址信息,以便消息接收方可以通过该地址进行回复。它包含了一个IPv4地址和端口号。
INFO_DST:用于指示消息的目标信息,包括消息接收方的主题识别符、实体ID和GUID等。它包含了一个Destination GUID Prefix(目标GUID前缀)和一个Entity ID(实体ID)。
INFO_REPLY:用于确认消息接收方是否成功接收了消息。它携带了一个Sequence Number Set(序列号集合),用于指示成功接收的消息序列号。
INFO_REQUEST:用于请求某些操作或数据。它携带了一个Sequence Number Set,用于指示请求的消息序列号。
INFO_REPLY_DELAY:用于指示回复延迟的时间间隔。它包含了一个Duration(延迟时间)。
INFO_HEARTBEAT:用于表示发布者或订阅者仍然处于活动状态,并且需要维护与其他实体之间的会话连接。它携带了一个First Sequence Number(起始序列号)和一个Last Sequence Number(最后序列号),用于描述当前发布者或订阅者的消息范围。
INFO_HEARTBEAT_FRAG:类似于INFO_HEARTBEAT,但用于传输分段数据。它携带了一个First Sequence Number和一个Last Sequence Number,以及分段数据的片段数量和索引。
INFO_DATA:用于传输实际的数据内容。该子消息通常包含序列号、内容数据和QoS(Quality of Service)信息等。它携带了一个Sequence Number(序列号)、一段数据内容和一些附加信息。
INFO_DATA_FRAG:类似于INFO_DATA,但用于传输分段数据。它携带了一个Sequence Number、分段数据的片段数量和索引,以及分段数据的片段内容。
INFO_ACKNACK:用于请求丢失的数据进行重传。它携带了一个Bitmap(位图),每个位表示一个消息序列号是否已经接收。
INFO_GAP:用于指示在序列号范围内缺失了哪些数据。它携带了一个Gap Start(缺失数据的起始序列号)和一个Gap List(缺失数据的序列号列表)。
这些是RTPS Submessage中INFO子消息的主要类型。具体使用哪些类型取决于具体的通信需求和协议配置。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值