Sunday, 7 May 2017

ESP8266 network broadcast

I've written a short sketch to show some of the calculations used for networking and broadcasts. This is for the NodeMCU using the Arduino IDE

I did this because I was looking for examples of networking and came across so many examples of incorrect assumptions and unnecessarily complicated code especially related to broadcast messages. It was difficult to isolate the correct information from the incorrect.

A big area of confusion is over broadcasts and multicast. These are two DIFFERENT things. Nearly always what people will want to use is BROADCAST.

Broadcasts are sent as normal packets but with the broadcast address as the destination. All clients receive broadcast packets that have been sent on their subnet. Broadcast packets are not forwarded by routers so they are just for the local network.
https://en.wikipedia.org/wiki/Unicast
https://en.wikipedia.org/wiki/Broadcasting_(networking)
https://en.wikipedia.org/wiki/Multicast

I see lots of assumptions about subnets. Most people's home networks are class C so simply changing the last octet to 255 makes it the broadcast address. That works for a class C subnet but is wrong for most other subnets.

Subnets can be any number of bits not just the common and simplified 8 bit class A, 16 bit class B or 24 bit class C.
https://en.wikipedia.org/wiki/Subnetwork

The network port is usually understood. Although any integer up to 65535 can be used, it is best to stay between 1024 and 65535. You can only read packets that are sent to the port being listened to.
It is probably best to pick a port not commonly used. There are list of registered ports usage.
https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

The following shows the calculation to get the broadcast address for any subnet and how to send broadcast packets.


#include "ESP8266WiFi.h"
#include "WiFiUdp.h"

// The port can be any integer between 1024 and 65535
const unsigned int NET_PORT = 58266;
// This uses the ESP8266 UDP class
WiFiUDP Udp;
// The network packet payload
char NetMsg_Something[] = "YourMessage";

// Let everyone else on the network know this device is present
void BroadcastPresence(){
  // Calculate this network broadcast address
  IPAddress broadcastIP = ~WiFi.subnetMask() | WiFi.gatewayIP();
  // A broadcast packet goes to every host on the subnet.
  // It is a NORMAL packet but sent to a specific address.
  Udp.beginPacket(broadcastIP, NET_PORT);
  Udp.write(NetMsg_Something);
  Udp.endPacket();
}



The example sketch that you can download from here requires two NodeMCU's running the same code so they can broadcast to each other.



Sending broadcast packets should be simple but there is some doubt if all WiFi Access Points forward network broadcast packets.
The broadcast packets worked on my network but if I find a network where they don't, it would be fairly easy to create a loop to send a unicast packet to all the possible IP addresses on any given subnet.

All that is needed is the first or last address on the network and the number of usable hosts. Those calculations are easy.


// This shows the very simple maths required to calculate some
// useful network information
void NetworkAddressCalculations(){
  // Calculate this network broadcast address
  IPAddress broadcastIP = ~WiFi.subnetMask() | WiFi.gatewayIP();
  Serial.println("Subnet broadcast address: " + broadcastIP.toString());
  // Calculate the network address
  IPAddress networkIP = WiFi.subnetMask() & WiFi.gatewayIP();
  Serial.println("Network address: " + networkIP.toString());
  // The number of usable host addresses might be usefull
  unsigned long numberOfAddresses = NumberOfHosts(WiFi.subnetMask());
  Serial.print("Number of host addresses: ");
  Serial.println(numberOfAddresses);
}

// Returns the number of usable hosts in a subnet
// The network address and the broadcast address are not usable by hosts
unsigned long NumberOfHosts(IPAddress subnet){
  subnet = ~subnet;
  return subnet[3] + (subnet[2] * 256) + (subnet[1] * 65536) + (subnet[0] * 16777216) -1;
}




The first address in a subnet is called the network address. The last address is always the broadcast address. The first and last addresses cannot be used for hosts on the network.

Although I've chosen to use the gateway address in the above examples, any address on the subnet works in the binary calculations so the following produce the exact same results for the broadcast address as we did using the gateway address in the above example:



IPAddress broadcastIP = ~WiFi.subnetMask() | WiFi.localIP();



The Internet Protocol (IP) was designed when every bit of processing power was precious and binary bit level calculations were and still are, quick to perform. Using the binary OR (|) in the above line of code and the binary AND (&) operator in the following line, the broadcast or network IP address result is the same regardless of which host IP address from within the subnet is used for the calculation.

In the following example using the local host IP produces the same network address as using the gateway IP did in the longer code sample above:


IPAddress networkIP = WiFi.subnetMask() & WiFi.localIP();



If you do create code that loops round all possible IP addresses be careful. A class B or worse a class A network has a lot of potential end points! Up to 16 million addresses on a Class A network.
Most home networks are class C so have a maximum of 254 addresses.

==

Download:
Network Broadcast Example (zip, Arduino C)

==

1 comment :

John C Brown said...

The breadboard in the photo in this post can be bought from Maplin in the UK.
http://www.maplin.co.uk/p/ad-01-solderless-breadboard-bz13p