• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Можно ли получить remote ip через UDP socket

kript0n

New member
Задача отослать с компа broadcast udp пакет, на esp его поймать и подключиться уже по TCP на порт, пришедший в пакете.

UDP socket создаю так:
Код:
    struct espconn *udp_listener = (struct espconn*)os_zalloc(sizeof(struct espconn));
    udp_listener->proto.udp = (esp_udp*)os_zalloc(sizeof(esp_udp));
    udp_listener->type = ESPCONN_UDP;
    udp_listener->state = ESPCONN_NONE;
    udp_listener->proto.udp->local_port = port;

    espconn_regist_recvcb(udp_listener, broadcast_recv_cb);
    espconn_create(udp_listener);
Пакет принимает, нормально обрабатывает. Но в
Код:
conn->proto.udp->remote_ip
всегда 192.168.0.0. Вот, собственно, и проблема.
 

kript0n

New member
Конечно же нужно использовать os_memcpy, а не os_strncpy.
 
Последнее редактирование:

Stelsing

New member
Добрый день, не хочу создавать новую тему, спрошу здесь.
Я не могу получить удаленный айпи из пришедшего пакета. Настраиваю так же как и автор, получаю так:
Код:
static void ICACHE_FLASH_ATTR UDP_receive_callback(void *arg, char *data, unsigned short len)
{
    struct espconn *test=(struct espconn *)arg;
    char info[150];
    os_sprintf(info,"Count - %d", _count);

    console_printf("Data_Received - %s\n\r", data);
    console_printf("Local IP - %d,", test->proto.udp->local_ip[0]);
    console_printf("%d,",  test->proto.udp->local_ip[1]);
    console_printf("%d,",  test->proto.udp->local_ip[2]);
    console_printf("%d\n\r",  test->proto.udp->local_ip[3]);
    console_printf("Local PORT - %d\n\r", test->proto.udp->local_port);
    console_printf("Remote IP - %d,", test->proto.udp->remote_ip[0]);
    console_printf("%d,",  test->proto.udp->remote_ip[1]);
    console_printf("%d,",  test->proto.udp->remote_ip[2]);
    console_printf("%d\n\r",  test->proto.udp->remote_ip[3]);
    console_printf("Remote PORT - %d\n\r", test->proto.udp->remote_port);


    espconn_sent(test, (uint8 *) info, (uint16) strlen(info));
    _count++;
}
При получении локальный айпи указан верно, удаленный нет - вместо него 0.0.0.0, порт аналогично 0. Но если настроить удаленный айпи и порт перед созданием сервера то все получаю правильно. Но мне надо узнать на какой айпи посылать ответ после получения запроса... Подскажите, что не так делаю?
 

Stelsing

New member
Жаль, что никто не знает...
выход из данной ситуации конечно есть - передавать в пакете еще и айпи от кого идет пакет, но как то это не правильно выглядит...
 

DVZ2010

New member
похоже ошибка в SDK при генерации события по callback ...recv_cb не заполняется удаленный IP и порт. Попробуй альтернативный вариант - через LWIP. Вышел февральский SDK 152. Проверил там то же самое.
 

pvvx

Активный участник сообщества
похоже ошибка в SDK при генерации события по callback ...recv_cb не заполняется удаленный IP и порт. Попробуй альтернативный вариант - через LWIP. Вышел февральский SDK 152. Проверил там то же самое.
Это как это так? Как тогда будут работать любые службы?
Код:
/** Function prototype for udp pcb receive callback functions
* addr and port are in same byte order as in the pcb
* The callback is responsible for freeing the pbuf
* if it's not used any more.
*
* ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
*            makes 'addr' invalid, too.
*
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @param port the remote port from which the packet was received
*/
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
Или вы про Ардуино или китай-espconn? В них без разницы - они не нужны. :)
 

Stelsing

New member
Конечно про epsconn, а какие еще есть нормальные варианты? LWIP?
В общем я хочу отправить на устройство UDP пакет, его получить и отправить результат обратно. Сейчас я отправляю широковещательным адресом, есть еще вариант отправлять в пакете свой айпи, на который будет возвращаться ответ.
Я только начал с этим модулем работать и есть еще куча вопросов, к примеру как принимать данные по юсарту, вроде ничего сложного нет, но по нормальному пока не получилось. Аналогично с созданием задач, получилось создать только одну задачу, создавал для каждого приоритета свою задачу, но работает только одна... никто не находил более менее нормального обучения по работе с этим модулем? может какие то уроки?
 

pvvx

Активный участник сообщества
вопрос, как понял, был про коллбэк китайского epsconn
Имеет слишком много ограничений для применения и жрет лишнюю память (не считая ошибок). По этой причине не нужна.
Даже не тянет на совместимость от одной версии SDK к другой. А Lwip как был в первом SDK, так и остался, без изменений.
C espconn для простых TCP и особенно UDP выходит более громоздкий код, чем с напрямую с Lwip.
Преимущество у espconn возможно было-бы в SSL, но китайцы так и не допили это, что и делает espconn ненужной надвеской.
 
Последнее редактирование:

rbalykov

New member
В документации вооще вон что пишут (SDK 1.5)
If it is a UDP transmission, please set espconn->proto.udp->remote_ip and
remote_port before every calling of espconn_send.
 

kript0n

New member
Вопрос остаётся вопросом: как, не перепиливая проект с SDK на meSDK, получить remote IP и remote Port через espconn?
Такая же проблема появилась при переезде на SDK 1.5.2. В 1.3 все работает нормально. Как вариант используй старую версию.
 

pvvx

Активный участник сообщества
Remote IP и порт из UDP пишется в espconn->pcommon.remote_ip и espconn->pcommon.remote_port
В честь чего remote IP должно записываться в proto.udp?
Открывайте исходники глюко-espconn и сморите:
Код:
static void ICACHE_FLASH_ATTR
espconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p,
                 struct ip_addr *addr, u16_t port) <---- ip и port !
{
    espconn_msg *precv = arg;
    struct pbuf *q = NULL;
    u8_t *pdata = NULL;
    u16_t length = 0;
    struct ip_info ipconfig;

    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb));

    precv->pcommon.remote_ip[0] = ip4_addr1_16(addr); <---- ip !
    precv->pcommon.remote_ip[1] = ip4_addr2_16(addr);
    precv->pcommon.remote_ip[2] = ip4_addr3_16(addr);
    precv->pcommon.remote_ip[3] = ip4_addr4_16(addr);
    precv->pcommon.remote_port = port; <---- port !
    precv->pcommon.pcb = upcb;
....
Но тут так никто не ответил - каков смысл использовать дублирование переменных pcb Lwip и двойное копирование в памяти буферов Lwip производимых espconn? Код при прямом обращении к Lwip не увеличивается размером. Может espconn вам нужна для уменьшения объема памяти и увеличения времени исполнения (для большей загрузки CPU) и ограничения кол-ва соединений в вашем ПО?
 
Последнее редактирование:

kript0n

New member
Remote IP и порт из UDP пишется в espconn->pcommon.remote_ip и espconn->pcommon.remote_port
В честь чего remote IP должно записываться в proto.udp?
Открывайте исходники глюко-espconn и сморите:
Код:
static void ICACHE_FLASH_ATTR
espconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p,
                 struct ip_addr *addr, u16_t port) <---- ip и port !
{
    espconn_msg *precv = arg;
    struct pbuf *q = NULL;
    u8_t *pdata = NULL;
    u16_t length = 0;
    struct ip_info ipconfig;

    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb));

    precv->pcommon.remote_ip[0] = ip4_addr1_16(addr); <---- ip !
    precv->pcommon.remote_ip[1] = ip4_addr2_16(addr);
    precv->pcommon.remote_ip[2] = ip4_addr3_16(addr);
    precv->pcommon.remote_ip[3] = ip4_addr4_16(addr);
    precv->pcommon.remote_port = port; <---- port !
    precv->pcommon.pcb = upcb;
....
Но тут так никто не ответил - каков смысл использовать дублирование переменных pcb Lwip и двойное копирование в памяти буферов Lwip производимых espconn? Код при прямом обращении к Lwip не увеличивается размером. Может espconn вам нужна для уменьшения объема памяти и увеличения времени исполнения (для большей загрузки CPU) и ограничения кол-ва соединений в вашем ПО?

Возможно я слегка припозднился с ответом. Обстоятельства вынуждают переезжать на 1.5.

Колбек из исходников использует почему-то espconn_msg. В моем же случае коллбек по приему данных использует espconn и выглядит так:
Код:
void broadcast_recv_cb(void *arg, char *data_ptr, unsigned short len)
Где arg есть espconn. А espconn_msg у меня вообще отсутсвует. То есть в принципе, нет такой структуры.

На счет того зачем espconn... Я не в курсе о том, как устроен lwip, доков на него я тоже не нашел, хотя и не особо искал. А espconn хоть как-то продокументирован китайцами. Так если все работает, и в принципе все устраивает, так зачем себе придумывать лишние проблемы с переписыванием всего с самого начала на lwip?
 

pvvx

Активный участник сообщества
На счет того зачем espconn... Я не в курсе о том, как устроен lwip, доков на него я тоже не нашел, хотя и не особо искал. А espconn хоть как-то продокументирован китайцами. Так если все работает, и в принципе все устраивает, так зачем себе придумывать лишние проблемы с переписыванием всего с самого начала на lwip?
В том то и дело, что espconn не позволяет работать. :) К примеру любой современный браузер открывает сразу 5 потоков (5 шт TCP соединений), а у меня модуль работает на более десятка одновременных соединений и ещё открыты несколько других портов UDP и TCP для разных сервисов.
Помигать светодиодом для блога на вечер espconn хватает... Этим и займитесь :D
 

kript0n

New member
В том то и дело, что espconn не позволяет работать. :) К примеру любой современный браузер открывает сразу 5 потоков (5 шт TCP соединений), а у меня модуль работает на более десятка одновременных соединений и ещё открыты несколько других портов UDP и TCP для разных сервисов.
Помигать светодиодом для блога на вечер espconn хватает... Этим и займитесь :D
Здорово, а вот мне нужено ровно одно соединение и если их становится больше, это уже ошибка. Поэтому espconn мне хватит за глаза, если он позволит мне получить IP. А диод к счастью уже мигает.
 
Сверху Снизу