Я улучшаю стек ROS (операционной системы робота) sql_database чтобы иметь возможность обрабатывать команды postgresqls LISTEN и NOTIFY. Как уже упоминалось, я использую libpq версии 9.1.10-0 на Ubuntu12.04 в программе на C ++.
Но по некоторым причинам я не могу получить УВЕДОМЛЕНИЕ.
Я знаю, что есть пример (Пример 28-2. Libpq Example Program 2), и он прекрасно работает. Я играл с ним довольно долго, а также пытался скопировать его в свой код как можно точнее и изменить пример кода таким образом, чтобы он был более похож на код, с которым у меня проблемы. Но это не помогло для моей проблемы.
Я могу получать уведомления в примере программы и при ручном входе в базу данных, но не в коде, который я хочу использовать.
Что еще я попробовал:
COMMIT;
после того, как я выполнил LISTEN <channel>;
команда. Но это вызвало предупреждение, как и ожидалось, поскольку у меня не было открытой транзакции.PQconsumeInput(connection_);
— это чисто живойУВЕДОМЛЕНИЕ всегда запускалось вручную с NOTIFY <channel>;
Код также можно увидеть здесь на GitHub (на нестабильных ветках):
класс PostgresqlDatabase (в sql_interface-> database_interface-> src на github)
Этот класс содержит соединение PGconn и предоставляет такие задачи, как
bool listenToChannel(std::string channel);
Основная цель этого класса — абстрагирование запросов sql, чтобы ROS-программисты больше не заботились о них.
класс databaseBinding
это клей между ROS и функциональностью базы данных. Он содержит объект PostgresqlDatabase для получения подключения к базе данных и для вызова задач.
Основная функция
Делает следующие вещи
PostgresqlDatabase::listenToChannel(std::string channel)
-функцииPostgresqlDatabase::checkNotify(notification &no)
-функцииФункция 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;
}
Так что оказалось, что с соединением что-то не так.
Он был создан с этим кодом:
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» и имел хорошее соединение.
Какое для меня неловкое и неудачное поведение.
Других решений пока нет …