SNMP Manager — несколько IP-адресов — проблема
У меня есть несколько SNMP-устройств в одной сети, и я пытаюсь запросить через номера OID каждое SNMP-устройство и назначить ответ в массив. Когда я запрашиваю один IP-адрес, я получаю правильный ответ, как и ожидалось.
Проблема: Если я запускаю один и тот же код в цикле for (несколько IP-адресов 192.168.1.150, 192.168.1.151 и т. д.), я получаю повторяющуюся информацию. Возможно, я использую неправильный метод обратного вызова, или диспетчер SNMP не может динамически изменить IP-адрес. Я изучил множество тем и испробовал множество способов, но не могу пройти мимо этого пункта.
Если кто-нибудь может мне помочь, это очень поможет!!
Пример вывода: Название модели и серийный номер должны быть разными для каждого IP-адреса
----------------------
192.168.8.150
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.151
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.152
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.153
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.154
KONICA MINOLTA bizhub C658
A79J021002278
Вот код
#if defined(ESP8266)
#include <ESP8266WiFi.h> // Основная библиотека WiFi ESP8266
#else
#include <WiFi.h> // Основная библиотека Wi-Fi ESP32
#endif
#include <string.h>
#include <WiFiUdp.h>
#include <Arduino_SNMP_Manager.h>
//******************************************
//* Информация о вашем WiFi *
//******************************************
const char *ssid = "Workmin_Sales";
const char *password = "workmin92429242";
//******************************************
//******************************************
//* Информация об устройстве SNMP *
//******************************************
const char *community = "public";
const int snmpVersion = 1; // Версия SNMP 1 = 0, Версия SNMP 2 = 1
// OID
const char *oidModelName = ".1.3.6.1.2.1.25.3.2.1.3.1"; // OctetString SysName
const char *oidSerialNumber = ".1.3.6.1.2.1.43.5.1.1.17.1"; // OctetString SysName
//******************************************
//******************************************
//* Настройки *
//******************************************
int pollInterval = 20000; // задержка в миллисекундах
//******************************************
//******************************************
//* Инициализация *
//******************************************
// Переменные
char *modelNameArray[5];
char *serialNumberArray[5];
char modelName[50];
char *modelNameResponse = modelName;
char serialNumber[50];
char *serialNumberResponse = serialNumber;
// Пустой указатель обратного вызова для каждого OID
ValueCallback *callbackSerialNumber;
ValueCallback *callbackModelName;
//******************************************
unsigned long pollStart = 0;
// SNMP-объекты
WiFiUDP udp; // Объект UDP, используемый для отправки и получения пакетов
SNMPManager snmp = SNMPManager(community); // Запускаем SMMPManager для прослушивания ответов на get-запросы
SNMPGet snmpRequest = SNMPGet(community, snmpVersion); // Запускает экземпляр SMMPGet для отправки запросов
//******************************************
//* Объявления функций *
//******************************************
void getSNMP();
//******************************************
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Ждем соединения
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to SSID: ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
snmp.setUDP(&udp); // даем snmp указатель на объект UDP
snmp.begin(); // запускаем SNMP-менеджер
}
void loop()
{
// поместите сюда ваш основной код для многократного запуска:
snmp.loop();
if (millis() - pollStart >= pollInterval)
{
pollStart += pollInterval; // это предотвращает дрейф в задержках
getSNMP();
// doSNMPCalculations(); // Делаем что-то с собранными данными
}
}
void getSNMP()
{
for (int i = 0; i < 5; i++) {
// Создаем SNMP-запрос на получение, добавляем каждый OID в запрос
IPAddress router(192, 168, 8, i + 150);
// Получаем обратные вызовы от создания обработчика для каждого из OID
callbackSerialNumber = snmp.addStringHandler(router, oidSerialNumber, &serialNumberResponse);
callbackModelName = snmp.addStringHandler(router, oidModelName, &modelNameResponse);
snmpRequest.addOIDPointer(callbackSerialNumber);
snmpRequest.addOIDPointer(callbackModelName);
snmpRequest.setIP(WiFi.localIP()); // IP прослушивающего MCU
// snmpRequest.setPort(501); // По умолчанию используется UDP-порт 161 для SNMP. Но при необходимости можно переопределить.
snmpRequest.setUDP(&udp);
snmpRequest.setRequestID(rand() % 5555);
snmpRequest.sendTo(router);
snmpRequest.clearOIDList();
delay(1000);
modelNameArray[i] = modelNameResponse;
serialNumberArray[i] = serialNumberResponse;
Serial.print("192.168.8.");
Serial.println(i + 150);
Serial.println(modelNameArray[i]);
Serial.println(serialNumberArray[i]);
Serial.println("----------------------");
}
}
@Christo Deyzel, 👍1
2 ответа
Лучший ответ:
Думаю, я вижу несколько проблем в приведенном выше примере.
snmpRequest.sendTo(router);
отправит SNMP-пакет. Но вам нужно вызватьsnmp.loop()
, чтобы прочитать входящие ответы на ваш запрос. Поэтому вам нужно реструктурировать код, чтобы вы могли вызывать loop() потенциально много раз, чтобы ждать входящих ответов, прежде чем читать и сохранять значения.serialNumberResponse
— указатель на массив символовserialNumber
(аналогично для модели). Если обратный вызов возвращает серийный номер123ABC
в первый раз, а следующее устройство называется1XD
, тогда массив будет иметь значение1XDABC
. Поэтому, если вы планируете повторно использовать переменную, вам нужно очищать ее между использованиями, например:memset(serialNumber, 0, sizeof(serialNumber));
- Поскольку вы не всегда можете получить успешный ответ или ответ в отведенное время, значение может оставаться пустым. Если вы хотите сохранить значения в другой переменной, вы можете убедиться, что они не пусто, так как это перезапишет значение, которое вы могли получить при предыдущем успешном вызове. Если вы имели дело с числами, значение также может быть значением предыдущего вызова. Как указано в ответе выше, вы имеете дело с указателями, поэтому, если вы хотите сохранить значение, вам нужно скопировать значение, иначе вы просто укажете на тот же указатель.
Я надеюсь, что это поможет указать вам правильное направление. Я добавил в библиотеку пример, показывающий, как можно запрашивать несколько устройств и сохранять результаты в массиве, см.: https://github.com/shortbloke/Arduino_SNMP_Manager/tree/master/examples/ESP_Multiple_SNMP_Device_Polling. Он сохраняет ответы непосредственно в массив. Это может привести к очистке значений в случае тайм-аута, я еще не проверял это полностью.
Мартин
Вы не сохраняете данные в своем массиве, вы сохраняете указатель на хранилище, где обратный вызов хранит свои данные. Таким образом, каждая запись получает один и тот же указатель на одно и то же хранилище, содержимое которого изменяется. Таким образом, все элементы массива видят одно и то же (последнее) содержимое.
Мне потребовалось много лет, чтобы как следует разобраться с указателями C.
Вместо того, чтобы просто присвоить (=
) значение, нужно скопировать содержимое.
Поскольку у вас есть только массив указателей, это можно сделать с помощью strdup()
, который выделяет новый блок ОЗУ и копирует в него содержимое. Обязательно используйте free()
для этого выделенного блока, когда закончите с ним.
- стрдуп
- Использование c_str() для String для IPAddress с NTPClient дает неправильные значения
- ESP32 со статическим IP-адресом, выступающим в качестве клиента, подключающегося к ESP32, выступающему в качестве точки доступа.
- ESP32 медленное время прохождения туда и обратно по Wi-Fi
- esp32, platformio A fatal error occurred: Packet content transfer stopped (received 8 bytes) *** [upload] Error 2
- Несколько клиентских серверов через Wi-Fi
- Как выбрать альтернативные контакты I2C на ESP32?
- Драйверы для чипа последовательного порта CH9102X
- Как преобразовать форматированный оператор print в строковую переменную?
Большое спасибо, Мартин. Я попробовал пример, и он работает без проблем! Когда у меня будут деньги, я куплю тебе пива :), @Christo Deyzel