• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Broadcast datagram to multiple recipients

Started by Patrice Terrier, October 06, 2015, 11:49:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Patrice Terrier

Broadcasting:
Occurs when a host sends a datagram to all other hosts on the network.
It is actually quite simple, just send packets to the specially designated broadcast address "255.255.255.255".
All hosts listening on the wire, will receive the same datagram, and it is limited to the local network only.

The main advantage is that the listeners do not need to know the server address, all they have to do is to wait for the incoming packets.

Example on how i am using it with a local WiFi (mixing Windows PC and Android tablets):
When playing audio live, the band leader uses it to trigger a new datagram (with lyric text) when moving from one section to another, to display the current vocal to sing altogether with the chord notations.
Another typical use, is to help musicians to be in sync: "1", "2", "3", "4", "start playing", or to use it as an extra "click track" (metronome).

The Sender'// Sender
'// Broadcast datagram to multiple recipients
'// Author Patrice Terrier
'// www.zapsolution.com
'// Date: 10-06-2015

#BREAK ON
#COMPILE EXE "Sender.exe"
#Include "win32api.inc"
#Include "time.inc"

%PORT_NUMBER = 8000
$DEST_ADDR   = "255.255.255.255"
%BUFFER_SIZE = 4096
%DELAY       = 1000

function pbmain() as long
    local lps as DWORD                    '// Socket descriptor of server
    local nDoIt, broadcast, current_time as long
    local sendaddr as sockaddr_in
    local recvaddr as sockaddr_in
    local wsa as WSADATA                  '// Used to open windows connection

    '// Open windows connection
    if (WSAStartup(&h0202, wsa)) then
        print "Could not open Windows connection."
        function = 0: exit function
    end if

    nDoIt = -1
    lps = socket(%AF_INET, %SOCK_DGRAM, byval %NULL)
    if (lps = %INVALID_SOCKET) then
        print "Could not create socket."
        lps = 0
        nDoIt = 0
    else
        broadcast = 1
        if (setsockopt(lps, %SOL_SOCKET, %SO_BROADCAST, broadcast, sizeof(long)) = -1) then
            print "Could not set socket option"
            nDoIt = 0
        end if
    end if
    if (nDoIt) then
        RtlFillMemory(byval varptr(sendaddr), sizeof(sockaddr_in), 0)
        sendaddr.sin_family = %AF_INET
        sendaddr.sin_port = htons(%PORT_NUMBER)
        sendaddr.sin_addr.s_addr = %INADDR_ANY

        if (bind(lps, sendaddr, sizeof(sockaddr_in)) = -1) then
            print "Could not bind name to socket."
        else
            print "Press the Escape key to STOP everything"
            RtlFillMemory(byval varptr(recvaddr), sizeof(sockaddr_in), 0)
            recvaddr.sin_family = %AF_INET
            recvaddr.sin_port = htons(%PORT_NUMBER)
            recvaddr.sin_addr.s_addr = inet_addr($DEST_ADDR)
            local zBuffer as asciiz * %BUFFER_SIZE
            local nSTOP as long
            local nTick as dword
            nTick = GetTickCount() + %DELAY
            do
                 RtlFillMemory(byval varptr(zBuffer), sizeof(zBuffer), 0)
                 if (asc(inkey$) = 27) then
                     zBuffer = "STOP"
                     nSTOP = 27
                 else
                     if (GetTickCount() > nTick) then
                         nTick = GetTickCount() + %DELAY
                         zBuffer = Time$
                     end if
                 end if
                 if (len(zBuffer)) then
                     print zBuffer
                     if (sendto(lps, zBuffer, sizeof(zBuffer), 0, recvaddr, sizeof(sockaddr_in)) <> sizeof(zBuffer)) then
                         print "Error sending datagram.": exit do
                     end if
                 end if
            loop until nSTOP = 27
        end if
    end if
    if (lps) then closesocket(lps)     

    WSACleanup()
    function = 0
end function


The Receiver'// Receiver
'// Broadcast datagram to multiple recipients
'// Author Patrice Terrier
'// www.zapsolution.com
'// Date: 10-06-2015

#BREAK ON
#COMPILE EXE "Receiver.exe"
#Include "win32api.inc"
#Include "time.inc"

%PORT_NUMBER = 8000
$DEST_ADDR   = "255.255.255.255"
%BUFFER_SIZE = 4096

function pbmain() as long
    local lps as DWORD                    '// Socket descriptor of server
    local nDoIt, broadcast, current_time as long
    local sendaddr as sockaddr_in
    local recvaddr as sockaddr_in
    local addr_len as long
    local wsa as WSADATA                  '// Used to open windows connection

    '// Open windows connection
    if (WSAStartup(&h0202, wsa)) then
        print "Could not open Windows connection."
        function = 0: exit function
    end if

    nDoIt = -1
    lps = socket(%AF_INET, %SOCK_DGRAM, byval %NULL)
    if (lps = %INVALID_SOCKET) then
        print "Could not create socket."
        lps = 0
        nDoIt = 0
    else
        broadcast = 1
        if (setsockopt(lps, %SOL_SOCKET, %SO_BROADCAST, broadcast, sizeof(long)) = -1) then
            print "Could not set socket option"
            nDoIt = 0
        end if
    end if
    if (nDoIt) then
        RtlFillMemory(byval varptr(recvaddr), sizeof(sockaddr_in), 0)
        recvaddr.sin_family = %AF_INET
        recvaddr.sin_port = htons(%PORT_NUMBER)
        recvaddr.sin_addr.s_addr = %INADDR_ANY
        if (bind(lps, recvaddr, sizeof(sockaddr_in)) = -1) then
            print "Could not bind name to socket."
        else
            print "Press Escape to quit"
            RtlFillMemory(byval varptr(sendaddr), sizeof(sockaddr_in), 0)
            sendaddr.sin_family = %AF_INET
            sendaddr.sin_port = htons(%PORT_NUMBER)
            sendaddr.sin_addr.s_addr = %INADDR_ANY

            local zBuffer as asciiz * %BUFFER_SIZE
            addr_len = sizeof(sendaddr)
            do
                if (recvfrom(lps, zBuffer, sizeof(zBuffer), 0, sendaddr, addr_len) < 0) then
                    print "Error receiving data."
                else
                    '// Display server message
                    print "Server message is: " + zBuffer
                    if (zBuffer = "STOP") then exit do
                end if
            loop until asc(inkey$) = 27
        end if
    end if
    if (lps) then closesocket(lps)     

    WSACleanup()
    function = 0
end function


The attached zip file comprise the source code and the compiled PBCC exe (console application).
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

Here is the translation into 32-bit C++ source code.

Sender
// Sender
// Broadcast datagram to multiple recipients
// Author Patrice Terrier
// www.zapsolution.com
// Date: 10-07-2015

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>

#define PORT_NUMBER 8000
#define BUFFER_SIZE 4096
#define DELAY       1000
const char* DEST_ADDR = "255.255.255.255";

int __cdecl main() {
    WSADATA wsa;                  // Used to open windows connection
    int nDoIt = 1, broadcast = 1, nStop = 0;
    DWORD nTick = 0;
    int nLen = sizeof(int);
    SOCKET lps;                   // Socket descriptor of server
    struct sockaddr_in sendaddr;  // Information about the server
    struct sockaddr_in recvaddr;  // Information about the client
    char zBuffer[BUFFER_SIZE];    // Where to store received data
    time_t current_time;          // Current time
    char zTime[26] = { 0 };

    // Open windows connection
    if (WSAStartup(0x0202, &wsa)) {
        fprintf(stderr, "Could not open Windows connection.\n");
        exit(0);
    }

    // Open a datagram socket
    lps = socket(AF_INET, SOCK_DGRAM, 0);
    if (lps == INVALID_SOCKET) {
        fprintf(stderr, "Could not create socket.\n");
        lps = 0;
        nDoIt = 0;
    } else {
        if (setsockopt(lps, SOL_SOCKET, SO_BROADCAST, (char*) &broadcast, nLen) == -1) {
            fprintf(stderr, "Could not set socket option.\n");
            nDoIt = 0;
        }
    }
    if (nDoIt) {
        RtlFillMemory((void*) &sendaddr, sizeof(sendaddr), '\0');
        sendaddr.sin_family = AF_INET;
        sendaddr.sin_port = htons(PORT_NUMBER);
        sendaddr.sin_addr.s_addr = INADDR_ANY;
        if (bind(lps, (struct sockaddr*) &sendaddr, sizeof(struct sockaddr_in)) == -1) {
            fprintf(stderr, "Could not bind to socket.\n");
        } else {
            fprintf(stderr, "Press the Escape key to STOP everything.\n");
            RtlFillMemory((void*)&recvaddr, sizeof(recvaddr), '\0');
            recvaddr.sin_family = AF_INET;
            recvaddr.sin_port = htons(PORT_NUMBER);
            recvaddr.sin_addr.s_addr = inet_addr(DEST_ADDR);
            nTick = GetTickCount() + DELAY;
            do {
                RtlFillMemory((void*) &zBuffer, sizeof(zBuffer), '\0');
                if (GetAsyncKeyState(VK_ESCAPE)) {
                    strcpy_s(zBuffer, sizeof(zBuffer), "STOP");
                    nStop = 27;
                } else {
                    if (GetTickCount() > nTick) {
                        nTick = GetTickCount() + DELAY;
                        current_time = time(NULL);
                        ctime_s(zTime, sizeof(zTime), &current_time);
                        strcpy_s(zBuffer, sizeof(zBuffer), zTime);
                    }
                }
                if (strlen(zBuffer)) {
                    fprintf(stderr, zBuffer);
                    if (sendto(lps, zBuffer, sizeof(zBuffer), 0, (struct sockaddr*) &recvaddr, sizeof(recvaddr)) != sizeof(zBuffer)) {
                        fprintf(stderr, "Error sending datagram.\n");
                        break;
                    }
                }
            } while (nStop != 27);
        }
    }
    if (lps) { closesocket(lps); }

    WSACleanup();
    return 0;
}


Receiver
// Receiver
// Broadcast datagram to multiple recipients
// Author Patrice Terrier
// www.zapsolution.com
// Date: 10-07-2015

#include <stdio.h>
#include <winsock.h>

#define PORT_NUMBER 8000
#define BUFFER_SIZE 4096
const char* DEST_ADDR = "255.255.255.255";

int __cdecl main() {
    WSADATA wsa;                  // Used to open windows connection
    int nDoIt = 1, broadcast = 1, nStop = 0;
    DWORD nTick = 0;
    int nLen = sizeof(int);
    SOCKET lps;                   // Socket descriptor of server
    struct sockaddr_in sendaddr;  // Information about the server
    struct sockaddr_in recvaddr;  // Information about the client
    char zBuffer[BUFFER_SIZE];    // Where to store received data

    // Open windows connection
    if (WSAStartup(0x0202, &wsa)) {
        fprintf(stderr, "Could not open Windows connection.\n");
        exit(0);
    }

    // Open a datagram socket
    lps = socket(AF_INET, SOCK_DGRAM, 0);
    if (lps == INVALID_SOCKET) {
        fprintf(stderr, "Could not create socket.\n");
        lps = 0;
        nDoIt = 0;
    }
    else {
        if (setsockopt(lps, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, nLen) == -1) {
            fprintf(stderr, "Could not set socket option.\n");
            nDoIt = 0;
        }
    }
    if (nDoIt) {
        RtlFillMemory((void*) &recvaddr, sizeof(recvaddr), '\0');
        recvaddr.sin_family = AF_INET;
        recvaddr.sin_port = htons(PORT_NUMBER);
        recvaddr.sin_addr.s_addr = INADDR_ANY;
        if (bind(lps, (struct sockaddr*) &recvaddr, sizeof(struct sockaddr_in)) == -1) {
            fprintf(stderr, "Could not bind to socket.\n");
        } else {
            fprintf(stderr, "Press the Escape key to quit.\n");
            RtlFillMemory((void*) &sendaddr, sizeof(sendaddr), '\0');
            sendaddr.sin_family = AF_INET;
            sendaddr.sin_port = htons(PORT_NUMBER);
            sendaddr.sin_addr.s_addr = INADDR_ANY;

            RtlFillMemory((void*)&zBuffer, sizeof(zBuffer), '\0');
            nLen = sizeof(sendaddr);
            do {
                if (GetAsyncKeyState(VK_ESCAPE)) {
                    fprintf(stderr, "STOP\n");
                    nStop = 27;
                } else {
                    if (recvfrom(lps, zBuffer, sizeof(zBuffer), 0, (struct sockaddr*) &sendaddr, &nLen) < 0) {
                        fprintf(stderr, "Error receiving datagram.\n");
                    } else {
                        fprintf(stderr, "Sender message is: ");
                        fprintf(stderr, zBuffer);
                        if (strcmp(zBuffer, "STOP") == 0) { nStop = 27; }
                    }
                }
            } while (nStop != 27);
        }
    }
    if (lps) { closesocket(lps); }

    WSACleanup();
    return 0;
}
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

Patrice,
  I thought you were coding only for 64 bit c++ ?

James

Patrice Terrier

#3
In that very specific case, datagrams are also sent to Android on the local network,
that means using 32-bit and Unicode.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com