上一节我们讲到ros的切入点,其中有初始化了网络模块

上一节原文链接:https://blog.csdn.net/lxj362343/article/details/126088735


//转换传入参数为remapping后调用调用此函数
void init(const M_string& remappings, const std::string& name, uint32_t options)
{
  if (!g_atexit_registered)
  {
    g_atexit_registered = true;
//atexit函数是一个特殊的函数,它是在正常程序退出时调用的函数,我们把他叫为登记函数,
// 一个进程可以登记32个函数,这些函数由exit自动调用,这些函数被称为终止处理函数,
//atexit函数可以登记这些函数。exit调用终止处理函数的顺序和atexit登记的顺序相反,
//如果一个函数被多次登记,也会被多次调用,也就是说退出时将调用atexitCallback这个函数。
    atexit(atexitCallback);
  }
 
  if (!g_global_queue)
  {
    g_global_queue.reset(new CallbackQueue);
  }
 
  if (!g_initialized)
  {
    g_init_options = options;
    g_ok = true;
 
    ROSCONSOLE_AUTOINIT;
    // Disable SIGPIPE
#ifndef WIN32
    signal(SIGPIPE, SIG_IGN);
#endif
    check_ipv6_environment();
    //network相关的初始化,调用的network命名空间下的init
    network::init(remappings);
    //master相关的初始化
    master::init(remappings);
    // names:: namespace is initialized by this_node
    this_node::init(name, remappings, options);
    file_log::init(remappings);
    param::init(remappings);
 
    g_initialized = true;
  }
}

network::init(remappings);

//network相关的初始化,调用的network命名空间下的init,在下面的文件中可以找到定义

ros_comm/clients/roscpp/src/libros/network.cpp

void init(const M_string& remappings)
{
  //从输入的命令行参数获取__hostname
  M_string::const_iterator it = remappings.find("__hostname");
  if (it != remappings.end())
  {
    g_host = it->second;
  }
  else
  {
   //从输入的命令行参数获取__ip,这个从下面的代码看其实就是环境变量ROS_IP
    it = remappings.find("__ip");
    if (it != remappings.end())
    {
      g_host = it->second;
    }
  }

  it = remappings.find("__tcpros_server_port");
  if (it != remappings.end())
  {
    try
    {
     //lexical_cast库进行”字面值“的转换,类似C中的atoi()函数,可以进行字符串与整数/浮点数之间的字面转换
      g_tcpros_server_port = boost::lexical_cast<uint16_t>(it->second);
    }
    catch (boost::bad_lexical_cast&)
    {
      throw ros::InvalidPortException("__tcpros_server_port [" + it->second + "] was not specified as a number within the 0-65535 range");
    }
  }

  if (g_host.empty())
  { 
    //determineHost这函数在下面,当命令行参数获取不到上面几个参数就从环境变量中读取,也就是说命令行优先级比较高
    g_host = determineHost();
  }
}

使用lexical_cast可以很容易的在数值和字符串之间转换,只需要在目标参数里面指出要转换的目标类型即可(参考自:https://blog.csdn.net/zhizhengguan/article/details/116988456)

int x = lexical_cast<int>("100");
    long y = lexical_cast<long>("2000");
    float pai = lexical_cast<float>("3.14159e5");
    double  e = lexical_cast<double>("2.71828");
    double f = lexical_cast<double>("1.414.x", 5);

环境变量ROS_HOSTNAMEROS_IP的获取

std::string determineHost()
{
  std::string ip_env;
  // First, did the user set ROS_HOSTNAME?
  if ( get_environment_variable(ip_env, "ROS_HOSTNAME")) {
    ROSCPP_LOG_DEBUG( "determineIP: using value of ROS_HOSTNAME:%s:", ip_env.c_str());
    if (ip_env.size() == 0)
    {
      ROS_WARN("invalid ROS_HOSTNAME (an empty string)");
    }
    return ip_env;
  }

  // Second, did the user set ROS_IP?
  if ( get_environment_variable(ip_env, "ROS_IP")) {
    ROSCPP_LOG_DEBUG( "determineIP: using value of ROS_IP:%s:", ip_env.c_str());
    if (ip_env.size() == 0)
    {
      ROS_WARN("invalid ROS_IP (an empty string)");
    }
    return ip_env;
  }

  // Third, try the hostname
  char host[1024];
  memset(host,0,sizeof(host));
  if(gethostname(host,sizeof(host)-1) != 0)
  {
    ROS_ERROR("determineIP: gethostname failed");
  }
  // We don't want localhost to be our ip
  else if(strlen(host) && strcmp("localhost", host))
  {
    return std::string(host);
  }

  // Fourth, fall back on interface search, which will yield an IP address

#ifdef HAVE_IFADDRS_H
  struct ifaddrs *ifa = NULL, *ifp = NULL;
  int rc;
  if ((rc = getifaddrs(&ifp)) < 0)
  {
    ROS_FATAL("error in getifaddrs: [%s]", strerror(rc));
    ROS_BREAK();
  }
  char preferred_ip[200] = {0};
  for (ifa = ifp; ifa; ifa = ifa->ifa_next)
  {
    char ip_[200];
    socklen_t salen;
    if (!ifa->ifa_addr)
      continue; // evidently this interface has no ip address
    if (ifa->ifa_addr->sa_family == AF_INET)
      salen = sizeof(struct sockaddr_in);
    else if (ifa->ifa_addr->sa_family == AF_INET6)
      salen = sizeof(struct sockaddr_in6);
    else
      continue;
    if (getnameinfo(ifa->ifa_addr, salen, ip_, sizeof(ip_), NULL, 0,
                    NI_NUMERICHOST) < 0)
    {
      ROSCPP_LOG_DEBUG( "getnameinfo couldn't get the ip of interface [%s]", ifa->ifa_name);
      continue;
    }
    //ROS_INFO( "ip of interface [%s] is [%s]", ifa->ifa_name, ip);
    // prefer non-private IPs over private IPs
    if (!strcmp("127.0.0.1", ip_) || strchr(ip_,':'))
      continue; // ignore loopback unless we have no other choice
    if (ifa->ifa_addr->sa_family == AF_INET6 && !preferred_ip[0])
      strcpy(preferred_ip, ip_);
    else if (isPrivateIP(ip_) && !preferred_ip[0])
      strcpy(preferred_ip, ip_);
    else if (!isPrivateIP(ip_) &&
             (isPrivateIP(preferred_ip) || !preferred_ip[0]))
      strcpy(preferred_ip, ip_);
  }
  freeifaddrs(ifp);
  if (!preferred_ip[0])
  {
    ROS_ERROR( "Couldn't find a preferred IP via the getifaddrs() call; I'm assuming that your IP "
        "address is 127.0.0.1.  This should work for local processes, "
        "but will almost certainly not work if you have remote processes."
        "Report to the ROS development team to seek a fix.");
    return std::string("127.0.0.1");
  }
  ROSCPP_LOG_DEBUG( "preferred IP is guessed to be %s", preferred_ip);
  return std::string(preferred_ip);
#else
  // @todo Fix IP determination in the case where getifaddrs() isn't
  // available.
  ROS_ERROR( "You don't have the getifaddrs() call; I'm assuming that your IP "
             "address is 127.0.0.1.  This should work for local processes, "
             "but will almost certainly not work if you have remote processes."
             "Report to the ROS development team to seek a fix.");
  return std::string("127.0.0.1");
#endif
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐