Page 1 of 2

Working UDP client on any version of IDF?

Posted: Sat Aug 10, 2019 4:01 pm
by jponko
Does any one have a working udp client example? The udp_client example in the examples/protocols/socket/udp_client doesn't seem to work. I've used Wireshark to try to capure the message sent but it doesn't send. The udp_server example works but I want an example that doesn't rely on getting its destination from the packet it receives. I just want to be able to setup a client with a destination ipv4 address, port and send packets. I suspect that there is a arp problem which would explain why the client doesn't send the packet. Maybe I'm the only one with this problem?

I've even tried compiling Linux udp client examples as well but they don't seem to work either. I'm using a ESP32-lyraT v4.3 board and esp idf v3.2.2. I plan on using the esp32 as a WiFi access point and it seems work with the udp_server code. I never thought that UDP would be this difficult to implement on the ESP32 compared to the ESP8266. The only reason I switched from the esp8266 to the esp32-lyrat board was because of its audio streaming capabilities that I will latter use to stream audio over UDP. Not being able to send UDP packets is no go for me. My development environment is run under Linux Mint 19.2. Anyone having any luck with UDP sendto :?

Re: Working UDP client on any version of IDF?

Posted: Mon Aug 12, 2019 4:24 am
by ESP_Sprite
As far as I know, the UDP examples should work - I think we even have testcases for those that get run whenever an esp-idf version gets released. What is your setup exactly?

Re: Working UDP client on any version of IDF?

Posted: Tue Dec 22, 2020 3:58 pm
by mcmega
I tried to build a project from examples (UDP Client).
It didn't work for me either. I changed the code a little (removed the standard checks).
I keep getting messages:

Code: Select all

UDP: Socket created, sending to 192.168.1.108:1900
UDP: Error occurred during sending: errno 118
UDP Socket Restarting
...
And so endlessly and quickly.
The vTaskDelay (2000 / portTICK_PERIOD_MS) doesn't even fire.
My code:

Code: Select all

#define HOST_IP_ADDR "255.255.255.255"
#define PORT 1900

static const char * TAG = "UDP";
static const char * payload = "Message from ESP32 ";

static void taskUDPClient(void * pvParameters) {
  char rx_buffer[128];
  int addr_family = 0;
  int ip_protocol = 0;
  while (1) {
    struct sockaddr_in dest_addr;
    dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(PORT);
    addr_family = AF_INET;
    ip_protocol = IPPROTO_IP;
    int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
    if (sock < 0) {
      send_uart("UDP", "Unable to create socket", NULL);
      break;
    }
    //send_uart("UDP", "Socket created, sending", NULL);
    ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, PORT);
    while (1) {
      int err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
      if (err < 0) {
        ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);[Codebox=c file=Untitled.c][/Codebox]
        break;
      }
      send_uart("UDP", "Message sent", NULL);

      struct sockaddr_in source_addr;
      socklen_t socklen = sizeof(source_addr);
      int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);

      if (len < 0) {
        /* Ошибка при получении */
        ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
        break;
      } else {
        /* Данные получены */
        rx_buffer[len] = '\0';
        send_uart("UDP", "Received Data", rx_buffer);
        if (strncmp(rx_buffer, "OK: ", 4) == 0) {
          send_uart("UDP", "Received expected message, reconnecting", NULL);
          break;
        }
      }
      vTaskDelay(2000 / portTICK_PERIOD_MS);
    }

    if (sock != -1) {
      send_uart("UDP", "Socket Restarting", NULL);
      shutdown(sock, 0);
      close(sock);
    }
  }
  vTaskDelete(NULL);
}

// Инициализация UDP Server
esp_err_t udpClientInit() {
  if (xTaskCreate(taskUDPClient, "taskUDPClient", 4096, NULL, 5, NULL) != pdPASS) {
    return ESP_FAIL;
  }
  return ESP_OK;
}
Any idea why it doesn't work?

Re: Working UDP client on any version of IDF?

Posted: Wed Dec 23, 2020 1:44 am
by ESP_Sprite
Are you sure WiFi is actually connected and your ESP32 has an IP before you start sending?

Re: Working UDP client on any version of IDF?

Posted: Wed Dec 23, 2020 6:13 am
by mcmega
Yes, 100%.
I also get the time from the server, and it is correct. The application works stably, nothing crashes.
I also started UDP Server and it works fine, returns packets stably.
The only thing is UDP Client.

Re: Working UDP client on any version of IDF?

Posted: Wed Dec 23, 2020 10:14 am
by ESP_Sprite
No idea what it might be. For shits and giggles, I copy-pasted your code into the udp_client app (from current esp-idf master) and I have absolutely no issues getting the packets sent. To be fair, your ESP-IDF version is quite old (and actually out of support by now) , so it may be that there's some differences there.Whoops, post I replied to is not OP.

Re: Working UDP client on any version of IDF?

Posted: Thu Dec 24, 2020 5:21 am
by mcmega
How should reception work if many devices answer?
After all, I'm sending a request, I pass through the reception 1 time (96 lines) and the delay ...
And if many devices respond, how do you handle them?
Is the delay in the right place set?
I should have many answers.

Re: Working UDP client on any version of IDF?

Posted: Fri Dec 25, 2020 2:18 pm
by mcmega
I need to send requests to the broadcast address not constantly, but once every 5 seconds and then wait 30 seconds. This part works provided that there is a device on the network that responds to requests.
The essence of the work is as follows:

I wrapped the data receiving block in a loop while (1)
I create a task taskListenExit to change the flag receiverLoopFlag (in order to exit the reception cycle)
I send a broadcast request and for 2 seconds I am in a receive cycle in order to receive responses from all devices
after 2 seconds I have to exit the receive loop and send the next request
The problem is, I cannot get out of the receive loop if there are no devices on the network (no response).
Tell me, am I doing something wrong?

Code: Select all

/* Receive data cycle status (for forced exit if no responses) */
bool receiverLoopFlag = 1;

/* The task of exiting the loop waiting for responses */
static void taskListenExit() {
  while (1) {
    vTaskDelay(SMALL_PERIOD_SCAN * 1000 / portTICK_PERIOD_MS);
    receiverLoopFlag = 0;
  }
}

static void taskUDPClient(void * pvParameters) {
  char rx_buffer[1024];
  int addr_family = 0;
  int ip_protocol = 0;
  while (1) {
    struct sockaddr_in dest_addr;
    dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(PORT);
    addr_family = AF_INET;
    ip_protocol = IPPROTO_IP;

    int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
    if (sock < 0) {
      break;
    }
    int iRequest = NUM_REQUESTS;
    /* Cycle of periodically sending a packet to search for devices */
    while (1) {
      int err = sendto(sock, SEARCH_PHRASE, strlen(SEARCH_PHRASE), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
      if (err < 0) {
        break;
      }
      receiverLoopFlag = 1;
      /* Waiting cycle for responses */
      while (receiverLoopFlag == 1) {
        struct sockaddr_in source_addr;
        socklen_t socklen = sizeof(source_addr);
        int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
        if (len < 0) {
          break;
        }
        if (len > 0) {
          /* Package processing */
        }
      }
      iRequest--;
      if (iRequest > 0) {
        vTaskDelay(SMALL_PERIOD_SCAN * 1000 / portTICK_PERIOD_MS);
      } else {
        vTaskDelay(LONG_PERIOD_SCAN * 1000 / portTICK_PERIOD_MS);
        iRequest = NUM_REQUESTS;
      }
    }
    if (sock != -1) {
      shutdown(sock, 0);
      close(sock);
    }
  }
  vTaskDelete(NULL);
  }
}

// INIT UDP Client
esp_err_t udpClientInit() {
  if (xTaskCreate(taskUDPClient, "taskUDPClient", 4096, NULL, 5, NULL) != pdPASS) {
    return ESP_FAIL;
  }
  if (xTaskCreate(taskListenExit, "taskListenExit", 4096, NULL, 4, NULL) != pdPASS) {
    return ESP_FAIL;
  }
  return ESP_OK;
}
Why am I not getting out of the loop

Code: Select all

while (receiverLoopFlag == 1)
I change the flag and the condition becomes false
I checked in the function of task static void taskListenExit(), it is called correctly and changes the value of the flag.

Re: Working UDP client on any version of IDF?

Posted: Mon Dec 28, 2020 1:25 am
by ESP_Sprite
You're not getting out of the loop because recvfrom() won't return until it received a packet. If it does not receive a packet, it will never return. One of the ways around this would be to e.g. use select() with a timeout to wait until either data becomes available on the socket or the timeout hits. This guarantees your program will continue whether or not it receives a response.

Re: Working UDP client on any version of IDF?

Posted: Mon Dec 28, 2020 7:05 am
by mcmega
Thanks for the advice!
But I still haven't figured out how to work with select ()
I used advanced settings

Code: Select all

struct timeval read_timeout;
read_timeout.tv_sec = UDPC_RESPONSE_TIMEOUT;
//...
setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, & read_timeout, sizeof read_timeout);
It works, but I don't know if it is correct.