3

我正在增强 ROS(机器人操作系统)堆栈sql_database以能够处理 postgresqls LISTEN 和 NOTIFY 命令。如前所述,我在 C++ 程序中的 Ubuntu12.04 上使用 libpq 版本 9.1.10-0。但由于某些原因,我无法检索通知。

我知道,有一个示例(示例 28-2.libpq 示例程序 2),它工作得非常好。我已经玩了很长时间,还尝试将它尽可能准确地复制到我的代码中,并以一种更类似于我遇到问题的代码的方式更改示例代码。但这对我的问题没有帮助。

我可以在示例程序和手动登录数据库中收到通知,但不能在我想使用的代码中收到通知。

我还尝试了什么:

  • 连接到不同的数据库 - 没有改变任何东西。
  • COMMIT;在我执行命令后执行LISTEN <channel>;。但这引起了预期的警告,因为我没有未结交易。
  • 在我做之前检查连接是否已经死PQconsumeInput(connection_);- 它纯粹是活着的
  • 在同一个函数中执行 LISTEN 命令,我正在检查 NOTIFY(使用断点在两者之间触发 NOTIFY) - 没有改变任何东西。

NOTIFY 总是手动触发NOTIFY <channel>;

代码结构

代码也可以在 github上看到(在不稳定的分支上):

  • class PostgresqlDatabase (in sql_interface->database_interface->src on github)
    这个类持有连接 PGconn 并提供如下任务

     bool listenToChannel(std::string channel);
    

    该类的主要目的是抽象 sql 查询,这样 ROS 程序员就不必再关心它们了。

  • class databaseBinding
    它是 ROS 和数据库功能之间的粘合剂。它拥有一个 PostgresqlDatabase 对象以获取数据库连接并调用任务。

  • 一个主要功能
    做以下事情

    1. 做一些 ROS 初始化的东西
    2. 创建一个 databaseBinding 对象,它将初始化一个 PostgresqlDatabase 对象,该对象建立与我的数据库的连接
    3. 调用PostgresqlDatabase::listenToChannel(std::string channel)-函数
    4. PostgresqlDatabase::checkNotify(notification &no)使用-function定期循环检查 NOTIFY

一些代码

检查通知

checkNotify 函数,每秒触发约 5 次:

/*! Checks for a received NOTIFY and returns it. */
bool PostgresqlDatabase::checkNotify(notification &no)
{
  PGnotify   *notify;
  PQconsumeInput(connection_);
  if ((notify = PQnotifies(connection_)) != NULL)
    {
    no.channel = notify->relname;
    no.sending_pid = notify->be_pid;
    no.payload = notify->extra;
    PQfreemem(notify);
    return true;
    } else
    {
    no.channel = "";
    no.sending_pid = 0;
    no.payload = "";
    PQfreemem(notify);
    return false;
    }
}

收听频道

/*! Listens to a specified channel using the Postgresql LISTEN-function.*/
bool PostgresqlDatabase::listenToChannel(std::string channel) {
  //look, if we're already listening to the channel in our list
  if (std::find(channels_.begin(),channels_.end(),channel) == channels_.end() )
    {
      std::string query = "LISTEN " + channel;
      PGresultAutoPtr result = PQexec(connection_,query.c_str());
      if (PQresultStatus(*result) != PGRES_COMMAND_OK)
          {
              ROS_WARN("LISTEN command failed: %s", PQerrorMessage(connection_));
              return false;
          }
      ROS_INFO("Now listening to channel \"%s\"",channel.c_str());
      channels_.push_back(channel);
      return true;
    }
  ROS_INFO("We are already listening to channel \"%s\" - nothing to be done",channel.c_str());
  return true;
}
4

1 回答 1

3

事实证明,连接有问题。它是使用该代码创建的:

void PostgresqlDatabase::pgMDBconstruct(std::string host, std::string port, 
std::string user, std::string password, std::string dbname )
{
  std::string conn_info = "host=" + host + " port=" + port +
    " user=" + user + " password=" + password + " dbname=" + dbname;
  connection_= PQconnectdb(conn_info.c_str());
  if (PQstatus(connection_)!=CONNECTION_OK)
  {
    ROS_ERROR("Database connection failed with error message: %s", PQerrorMessage(connection_));
  }
}

host=192.168.10.100, port=5432, user=turtlebot, password= , dbname=rosdb.
但是,一个空的用户名不满足 PQconnectdb 的使用,由于某种解析原因,导致它登录到数据库“turtlebot” 。不幸的是,该数据库存在于我的服务器上。而且它 - 当然 - 没有在“rosdb”数据库中发送任何通知并且连接良好。

对我来说,这是多么尴尬和不幸的行为。

于 2013-12-10T22:07:29.723 回答