Recent

Author Topic: Advice and or examples for broadcasting data on a LAN to multiple destinations  (Read 1000 times)

andyf97

  • New Member
  • *
  • Posts: 21
So chaps,

I have 200 Raspberry pies sitting on a Local LAN, each with a fixed IP address 192.168.0.X, where X is a consecutive range starting with 2

I want to send a bunch of bytes to all of those pies. instructions intended to get the pies doing a task approximately at the same time. Like to send a GO to them.

Is this possible and what would be the way to go with Lazarus ideally without third party extensions.

Can all pies receive data at the same time.











dbannon

  • Hero Member
  • *****
  • Posts: 3178
    • tomboy-ng, a rewrite of the classic Tomboy
What you are  taking about is called "multicast", was popular in some of the early video conferencing models but network engineers hated it. But within one subnets, should be possible. I have used it but have no idea what happens under the  surface other than the apps at all ends must be doing multicast.

Perhaps googling for 'multicast' would be a good start.

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Zvoni

  • Hero Member
  • *****
  • Posts: 2782
My first try would be Sockets and/or one of the network-libs
synapse, indy, lnet
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Warfley

  • Hero Member
  • *****
  • Posts: 1832
You basically have two options, either you use UDP Broadcast, this will send a message to all devices in the network. Otherwise you connect to each device individually and send a message to them.

For the UDP broadcast, every network has a broadcast address which ends in 255. You can just send an UDP to that address and everyone listening on the network should receive it. Here is a simple example using the sockets unit:
Code: Pascal  [Select][+][-]
  1. program broadcast_example;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$Assertions on}
  5.  
  6. uses
  7.   cthreads, SysUtils, Classes, Sockets;
  8.  
  9.  
  10. procedure Broadcaster;
  11. var
  12.   Sock: Tsocket;
  13.   Addr: TInetSockAddr;
  14.   Msg: String = 'Hello Broadcast';
  15.   OptVal, SetOptResult: Integer;
  16.   SendLen: SizeInt;
  17. begin
  18.   // Wait for receiver to be setup
  19.   Sleep(1000);
  20.  
  21.   Sock := fpsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  22.   Assert(Sock > 0, 'Error Creating Socket');
  23.   OptVal := 1;
  24.   SetOptResult := fpsetsockopt(Sock, SOL_SOCKET, SO_BROADCAST, @OptVal, SizeOf(OptVal));
  25.   Assert(SetOptResult = 0, 'Error Setting Broadcast');
  26.  
  27.   WriteLn('Sending BroadCast: "', Msg, '"');
  28.   // Send Broadcast
  29.   Addr.sin_family := AF_INET; // IPv4 Addr
  30.   Addr.sin_addr := StrToNetAddr('127.255.255.255'); // Broadcast addr
  31.   Addr.sin_port := htons(1337); // Port
  32.   SendLen := fpsendto(Sock, @Msg[1], Msg.Length, 0, @Addr, SizeOf(Addr));
  33.   Assert(SendLen = Msg.Length, 'Error Sending Message');
  34. end;
  35.  
  36. procedure Receiver;
  37. var
  38.   Sock: Tsocket;
  39.   ListenAddr: TInetSockAddr;
  40.   Msg: String;
  41.   SenderAddrLen: tsocklen;
  42.   SenderAddr: TInetSockAddr;
  43.   MessageLen: SizeInt;
  44. begin
  45.   Sock := fpsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  46.   Assert(Sock > 0, 'Error Creating Socket');      
  47.  
  48.   ListenAddr.sin_family := AF_INET; // IPv4 Addr
  49.   ListenAddr.sin_addr := StrToNetAddr('0.0.0.0'); // Receive over any NIC
  50.   ListenAddr.sin_port := htons(1337); // Listening Port
  51.   fpbind(Sock, @ListenAddr, SizeOf(ListenAddr));
  52.  
  53.   SetLength(Msg, 512); // Max UDP Datagram length
  54.   SenderAddrLen := SizeOf(SenderAddr);
  55.   MessageLen := fprecvfrom(Sock, @Msg[1], Length(Msg), 0, @SenderAddr, @SenderAddrLen);
  56.   SetLength(Msg, MessageLen);
  57.   WriteLn('Received Message [', HostAddrToStr(SenderAddr.sin_addr), ':',
  58.           NToHs(SenderAddr.sin_port), ']: ', Msg);
  59. end;
  60.  
  61. var
  62.   BCThread: TThread;
  63.   RCThread: TThread;
  64. begin
  65.   // As I don't have two PCs at hand, I will simply use two threads and the loopback address
  66.   BCThread := TThread.CreateAnonymousThread(@Broadcaster);
  67.   RCThread := TThread.CreateAnonymousThread(@Receiver);
  68.   BCThread.FreeOnTerminate := False;
  69.   RCThread.FreeOnTerminate := False;
  70.   BCThread.Start;
  71.   RCThread.Start;
  72.   BCThread.WaitFor;
  73.   BCThread.Free;
  74.   RCThread.WaitFor;
  75.   RCThread.Free;
  76. end.
  77.  

A few notes: Not every network supports broadcasting, e.g. the Internet doesn't (i.e. you can't just send a message to 255.255.255.255 and expect it be sent to all devices on the internet). Check your router if it doesn't work.

In the example above I have used the broadcast address of the loopback address, because I tested it locally (and broadcast will not be received by the PC that send it). For you the broadcasting address will be either 192.168.0.255 or 192.168.255.255 depending if you have a 24 or 16 bit subnet (if anything in between it's of course different).

Lastly, for simplicety I have bound the receiver to 0.0.0.0, which means it can receive messages from any network interface, meaning it would receive messages from the loopback (as in this example), from the cable network or from the wireless network, as those are the 3 network interfaces my computer currently has. If your devices have multiple network interfaces, you may want to restrict this to a specific IP address on one interface, to not get any "surprise" messages.

Also a note of caution, while the code above is written to be OS agnostic, i.e. run on windows and on Linux, Windows has this really annoying property of not liking pointers to the stack for some datastructures, see https://stackoverflow.com/questions/861154/winsock-error-code-10014
So when you encounter an 10014 error, you may need to put the addr data on the heap (using pointers and new/dispose)
« Last Edit: June 13, 2023, 11:51:46 am by Warfley »

 

TinyPortal © 2005-2018