.netarduinoudpesp32broadcast

ESP32 Successfully Sends UDP Packets, but .NET Program Fails to Receive Them


I have been trying to set up a simple UDP handshake function on an ESP32 that broadcasts packets over my local network on a specific port, so a .NET application running on a PC (Win10) on the same network may be able to receive them and perform said handshake.

The odd issue I'm encountering is that while I can fully confirm that the ESP32 is broadcasting and receiving properly. (Confirmed packets Via Wireshark & also was able to receive said UDP packets using a python UDP script on the same PC) I am unable to get the .NET client to register anything from the ESP32.

I am able to get it to register broadcast packets from another .NET test program on the same PC (Both over 127.0.0.1 & 192.168.1.255), but nothing else I've tried with the ESP32 seems to get through.

From my limited knowledge about windows Firewall nothing seems to be getting in the way there. So I would greatly appreciate it if anybody more knowledgeable could point me in the right direction.

Code:

ESP32 firmware (Arduino framework via VScode PlatformIO)

#include <Arduino.h>
#include <WiFiManager.h>
#include <WiFiUdp.h>

#define BAUDRATE 115200

//UDP
WiFiUDP udp;               // UDP object
const unsigned int port = 12345;  // Port for UDP communication

bool discovered = false;

// Timing variables for sending broadcast packets
unsigned long lastBroadcastTime = 0;
unsigned long broadcastInterval = 2000; // Interval between broadcasts (ms)

void handshakeBroadcast() {
  IPAddress broadcastIP = WiFi.localIP();
  broadcastIP[3] = 255; // Set the last octet to 255 for broadcast
  Serial.print("Broadcast Address: ");
  Serial.println(broadcastIP);


  String message = "Discovery request from ESP32";
    udp.beginPacket(broadcastIP, port);
    udp.print(message.c_str());
    udp.endPacket();
  if (udp.endPacket() == 1) {
        Serial.println("Packet sent successfully");
    } else {
        Serial.println("Error sending packet");
    }
}

void receiveUDP() {
  // Check for incoming UDP messages
  char incomingPacket[255];
  int packetSize = udp.parsePacket();

  if (packetSize) {
    int len = udp.read(incomingPacket, 255);
    if (len > 0) {
      incomingPacket[len] = 0; // Null-terminate the string
    }
    Serial.printf("Received UDP packet from %s:%d\n", 
                  udp.remoteIP().toString().c_str(), udp.remotePort());
    Serial.printf("Packet contents: %s\n", incomingPacket);

    // Respond to the sender
    udp.beginPacket(udp.remoteIP(), udp.remotePort());
    udp.print("Hello from ESP32!");
    udp.endPacket();
  }
}


void loop() {
  // Check for incoming UDP messages
  receiveUDP();
  
  //if Pc client not discovered Boradcast Handshake
  unsigned long currentMillis = millis(); // Non-blocking UDP broadcast sending
  if (currentMillis - lastBroadcastTime >= broadcastInterval)
  {
    handshakeBroadcast();
    lastBroadcastTime = currentMillis;  // Update last broadcast time
  }


}


void setup() {
    Serial.begin(115200);
    
    //WiFiManager, Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wm;

    bool res;
    res = wm.autoConnect("ESP32-Thing","12345678"); // password protected ap MIN 8 CHARACTERS

    if(!res) {
        Serial.println("Failed to connect");
        // ESP.restart();
    } 
    else {
        // WiFi connected
        Serial.println("Wifi connected.");
        
        Serial.print("IP: ");
        Serial.println(WiFi.localIP());
        
        Serial.print("Subnet mask: ");
        Serial.println(WiFi.subnetMask());

        // Start UDP
        if (udp.begin(port)) {
          Serial.printf("UDP listener started on port: %d\n", port);
        } else {
          Serial.println("Failed to start UDP listener");
        }
    } 
}

.NET program running on Win10 PC:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

class UdpBroadcastListener
{
    static void Main(string[] args)
    {
        int port = 12345; // Port to listen on

        IPAddress ANY = IPAddress.Parse("0.0.0.0");
        
        UdpClient udpClient = new UdpClient(port);
        IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, port); // Listen on all interfaces 
        Console.WriteLine($"Listening for broadcasts on port {port}...");

        while (true)
        {
            try
            {
                byte[] receivedBytes = udpClient.Receive(ref remoteEndPoint);
                string receivedMessage = Encoding.UTF8.GetString(receivedBytes);
                Console.WriteLine($"Received packet from {remoteEndPoint} with message: {receivedMessage}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }
    }
}

The Python script that confirms the PC is receiving the packets just fine:

import socket

# Configuration
UDP_IP = "0.0.0.0"  # Listen on all interfaces
UDP_PORT = 12345    # Port to listen on

# Create the UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Bind the socket to the specified IP and port
sock.bind((UDP_IP, UDP_PORT))

print(f"Listening for UDP packets on {UDP_IP}:{UDP_PORT}...")

try:
    while True:
        # Receive data from the socket (buffer size of 1024 bytes)
        data, addr = sock.recvfrom(1024)
        print(f"Received message: {data.decode('utf-8')} from {addr}")
except KeyboardInterrupt:
    print("\nExiting...")
finally:
    sock.close()

If you need any more info just let me know. Thank you so much for your time.


Solution

  • So turns out it wasn't actually the code itself that was the issue. I did more messing around with the firewall trying to figure out why other programs were receiving packets and my .NET program wasn't; and it turns out that it was actually firewall rules that were blocking the incoming packets, but for an odd reason.

    Because when running your .NET code in Visual Studio compiles the program down to an .exe, windows prompts you to select firewall rules for the application communicating on either public or private networks. When I first ran my project, I unchecked the public network box and only checked the private network box because that's what I usually do. But apparently not having the public network box checked was blocking the incoming packets from my ESP32. I have never encountered this issue before and I will probably look into my network settings further to find the root of the issue. (New contract and router form provider likely frazzled a few things)

    But TL;DR - Removing all firewall rules for incoming packets for the application, and then checking the public network option when I ran the .exe again and was prompted finally allowed the packets through.

    If anyone is willing to give any more tips I would greatly appreciate it as someone new to .NET and UDP in general. Thanks.