节点是如何调用XMLRPC的

描述

节点间通过XMLRPC建立连接

在一个节点刚启动的时候,它并不知道其它节点的存在,更不知道它们在交谈什么,当然也就谈不上通信。

所以,它要先与master对话查询其它节点的状态,然后再与其它节点通信。

而节点与master对话使用的就是XMLRPC。

从这一点来看,master叫节点管理器确实名副其实,它是一个大管家,给刚出生的节点提供服务。

下面我们以两个节点:talker和listener为例,介绍其通过XMLRPC建立通信连接的过程,如下图所示。

管理器

  1. talker注册

假设我们先启动talker。启动后,它通过1234端口使用XMLRPC向master注册自己的信息,包含所发布消息的话题名。master会将talker的注册信息加入注册列表中;

2.listener注册

listener启动后,同样通过XMLRPC向master注册自己的信息,包含需要订阅的话题名;

3.master进行匹配

master根据listener的订阅信息从注册列表中查找,如果没有找到匹配的发布者,则等待发布者的加入,如果找到匹配的发布者信息,则通过XMLRPC向listener发送talker的地址信息。

4.listener发送连接请求

listener接收到master发回的talker地址信息,尝试通过XMLRPC向talker发送连接请求,传输订阅的话题名、消息类型以及通信协议(TCP或者UDP);

5.talker确认连接请求

talker接收到listener发送的连接请求后,继续通过XMLRPC向listener确认连接信息,其中包含自身的TCP地址信息;

6.listener尝试与talker建立连接

listener接收到确认信息后,使用TCP尝试与talker建立网络连接。

7.talker向listener发布消息

成功建立连接后,talker开始向listener发送话题消息数据,master不再参与。

从上面的分析中可以发现,前五个步骤使用的通信协议都是XMLRPC,最后发布数据的过程才使用到TCP。

master只在节点建立连接的过程中起作用,但是并不参与节点之间最终的数据传输。

节点在请求建立连接时会通过master.cpp文件中的execute()函数调用XMLRPC库中的函数。

我们举个例子,加入talker节点要发布消息,它会调用topic_manager.cpp中的TopicManager::advertise()函数,在函数中会调用execute()函数,该部分代码如下。

XmlRpcValue args, result, payload;
  args[0] = this_node::getName();
  args[1] = ops.topic;
  args[2] = ops.datatype;
  args[3] = xmlrpc_manager_- >getServerURI();
  master::execute("registerPublisher", args, result, payload, true);

其中,registerPublisher就是一个远程过程调用的方法(或者叫函数)。节点通过这个远程过程调用向master注册,表示自己要发布发消息了。

你可能会问,registerPublisher方法在哪里被执行了呢?我们来到ros_comm-noetic-develtoolsrosmastersrcrosmaster路径下,打开master_api.py文件,然后搜索registerPublisher这个方法,就会找到对应的代码,如下。

匆匆扫一眼就知道,它在通知所有订阅这个消息的节点,让它们做好接收消息的准备。

你可能注意到了,这个被调用的XMLRPC是用python语言实现的。

也就是说,XMLRPC通信时只要报文的格式是一致的,不管C++还是python语言,都可以实现远程调用的功能。

def registerPublisher(self, caller_id, topic, topic_type, caller_api):
        try:
            self.ps_lock.acquire()
            self.reg_manager.register_publisher(topic, caller_id, caller_api)
            # don't let '*' type squash valid typing
            if topic_type != rosgraph.names.ANYTYPE or not topic in self.topics_types:
                self.topics_types[topic] = topic_type
            pub_uris = self.publishers.get_apis(topic)
            sub_uris = self.subscribers.get_apis(topic)
            self._notify_topic_subscribers(topic, pub_uris, sub_uris)
            mloginfo("+PUB [%s] %s %s",topic, caller_id, caller_api)
            sub_uris = self.subscribers.get_apis(topic)            
        finally:
            self.ps_lock.release()
        return 1, "Registered [%s] as publisher of [%s]"%(caller_id, topic), s
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分