我正在增强 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 对象以获取数据库连接并调用任务。一个主要功能
做以下事情- 做一些 ROS 初始化的东西
- 创建一个 databaseBinding 对象,它将初始化一个 PostgresqlDatabase 对象,该对象建立与我的数据库的连接
- 调用
PostgresqlDatabase::listenToChannel(std::string channel)
-函数 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;
}