Я пишу приложение на C ++, которое необходимо будет подключать к различным ПЛК по протоколу Modbus, IP-адреса этих ПЛК определяются пользовательским вводом. В настоящее время, когда пользователь вводит IP-адрес, к которому невозможно подключиться, моя программа зависает примерно на 2 минуты, пытаясь подключиться, а зависание моего приложения на 2 минуты — не вариант.
Пример программы иллюстрирует проблему и мои попытки исправить:
#include <modbus/modbus.h>
#include <string>
#include <errno.h>
#include <iostream>
#define PRINT_TIMEVAL(timeval) std::cout << "timeval sec: " << timeval.tv_sec << " usec: " << timeval.tv_usec << std::endl;
int main()
{
std::string ip = "192.168.2.5";
int port = 502;
int slaveNum = 1;
int address = 1;
int nb = 1;
struct timeval currentTimeout;
struct timeval responseTimeout;
responseTimeout.tv_sec = 1;
responseTimeout.tv_usec = 0;
struct timeval byteTimeout;
byteTimeout.tv_sec = 1;
byteTimeout.tv_usec = 0;
modbus_t *mb = modbus_new_tcp(ip.c_str(), port);
modbus_set_debug(mb, true);
modbus_set_error_recovery(mb, MODBUS_ERROR_RECOVERY_NONE);
modbus_flush(mb);
modbus_set_slave(mb, slaveNum);
modbus_get_response_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
modbus_set_response_timeout(mb, &responseTimeout);
modbus_get_response_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
modbus_get_byte_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
modbus_set_byte_timeout(mb, &byteTimeout);
modbus_get_byte_timeout(mb, ¤tTimeout);
PRINT_TIMEVAL(currentTimeout);
std::cout << "About to connect to " << ip << std::endl;
int errno;
if((errno = modbus_connect(mb)))
{
std::cout << "Error when connecting: " << modbus_strerror(errno) << std::endl;
}
std::cout << "Done connecting to " << ip << std::endl;
modbus_close(mb);
modbus_free(mb);
return 0;
}
Как вы можете видеть, я попытался установить переменные времени ответа и байта на 1 секунду (я также пробовал 500 и 5000 микросекунд). Когда я читаю значения времени ожидания, они были установлены правильно, поэтому я предполагаю, что они не имеют никакого отношения к первоначальной попытке подключения. Я также попытался явно установить режим восстановления после ошибки в none, если он пытался восстановить соединение самостоятельно.
Я хотел бы что-то, что будет либо останавливать modbus_connect через x промежуток времени, либо другую команду, которая позволит мне проверить, является ли IP действительным, прежде чем пытаться подключиться через modbus, это также потребует тайм-аута через короткий промежуток времени.
Я использую libmodbus версии 3.0.1-2
Проблема была с моей версией libmodbus (3.0.1), которая является текущей версией выпуска. В той версии они использовали Linux connect
команда, но они не передавали NONBLOCKING
флаг, таким образом connect
будет заблокирован на 2m7s. Мы решили эту проблему путем обновления до libmodbus v3.1.1, который помечен как нестабильный, но не находится в активной разработке (они разрабатываются на v3.1.2). К сожалению, эта версия libmodbus не работает для Windows.
Используйте потоки для прослушивания каждого устройства и помещайте эти сообщения в очередь, которую можно обрабатывать, не задерживая другие потоки.