App to demonstrate UDP broadcast datagrams using wxDatagramSocket

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
CJS
Earned a small fee
Earned a small fee
Posts: 17
Joined: Thu Jan 28, 2016 8:21 am

App to demonstrate UDP broadcast datagrams using wxDatagramSocket

Post by CJS »

Given the lack of suitable working examples or documentation about sending broadcast datagrams in wxWidgets that I encountered when researching it, I have put together this working demo app for the wxWidgets community on this forum where I found several useful leads, including boxcarmiba Wed Aug 02, 2006 at viewtopic.php?t=9410

Sending broadcast messages is useful for things like discovering how many of a particular resource are currently available, synchronising states, instant messaging, enumerating the devices on a network of "internet of things" devices, etc.

To build in Code::Blocks just create a new empty Frame-based wxWidgets 2.8.12 project and add the 4 files to the project. This example used the wxSmith GUI builder, only the File / Send menu command needs to be added, with ID idMenuSend, var name MenuItem3, and EVT_MENU handler BroadcastFrame::OnMenuItemSendSelected().

Test environment:
IDE: Code::Blocks nightly build svn 10136
wxWidgets version: 2.8.12 (the current recommended version of wxWidgets to use with Code::Blocks), Unicode build, static link
OS: MS Windows 7 (32-bit)
Compiler: TDM mingw ver 4.9.2

Using the File / Send menu command should result in a UDP broadcast message being sent and received on a log message box showing the message, i.e. "Test using port..." If you have another instance running on another computer on your local network it should also show the same message (if permitted by firewalls).

Main header:

Code: Select all

/***************************************************************
 * Name:      BroadcastMain.h
 * Purpose:   Defines Application Frame
 *            wxWidgets 2.8.12 sample to send and receive a UDP broadcast datagram
 * Author:    CJS ()
 * Created:   2016-01-27
 * Copyright: CJS ()
 * License:
Excepting if sections are specifically annotated that other
conditions apply, the following MIT license shall apply:

Copyright (c) 2016 CJS
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   https://opensource.org/licenses/MIT

 **************************************************************/

#ifndef BROADCASTMAIN_H
#define BROADCASTMAIN_H

//(*Headers(BroadcastFrame)
#include <wx/menu.h>
#include <wx/frame.h>
#include <wx/statusbr.h>
//*)

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#  pragma hdrstop
#endif

// for all others, include the necessary headers
#ifndef WX_PRECOMP
#  include "wx/wx.h"
#endif

#include "wx/socket.h"

#define MY_SERVER_PORT 57343

class BroadcastFrame: public wxFrame
{
    public:

        BroadcastFrame(wxWindow* parent,wxWindowID id = -1);
        virtual ~BroadcastFrame();

        void Init_Datagram_Socket();
        void OnUDPEvent(wxSocketEvent& event);

    private:

        //(*Handlers(BroadcastFrame)
        void OnQuit(wxCommandEvent& event);
        void OnAbout(wxCommandEvent& event);
        void OnMenuItemSendSelected(wxCommandEvent& event);
        //*)

        //(*Identifiers(BroadcastFrame)
        static const long idMenuQuit;
        static const long idMenuSend;
        static const long idMenuAbout;
        static const long ID_STATUSBAR1;
        //*)

        //(*Declarations(BroadcastFrame)
        wxMenuItem* MenuItem3;
        wxStatusBar* StatusBar1;
        //*)

        wxIPV4address m_BroadCastAddress; // For broadcast sending
        wxIPV4address m_LocalAddress;     // For listening
        wxDatagramSocket* m_Listen_Socket;

        DECLARE_EVENT_TABLE()
};

#endif // BROADCASTMAIN_H
Main implementation:

Code: Select all

/***************************************************************
 * Name:      BroadcastMain.cpp
 * Purpose:   Code for Application Frame
 *            wxWidgets 2.8.12 sample to send and receive a UDP broadcast datagram
 * Author:    CJS ()
 * Created:   2016-01-27
 * Copyright: CJS ()
 * License:
Excepting if sections are specifically annotated that other
conditions apply, the following MIT license shall apply:

Copyright (c) 2016 CJS
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   https://opensource.org/licenses/MIT

 **************************************************************/

#include "BroadcastMain.h"
#include <wx/msgdlg.h>

//(*InternalHeaders(BroadcastFrame)
#include <wx/intl.h>
#include <wx/string.h>
//*)

// Event ID numbers:
enum
{
    UDP_SOCKET = 200
};

// helper functions (standard wxSmith boilerplate)
enum wxbuildinfoformat
{
    short_f, long_f
};

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}

//(*IdInit(BroadcastFrame)
const long BroadcastFrame::idMenuQuit = wxNewId();
const long BroadcastFrame::idMenuSend = wxNewId();
const long BroadcastFrame::idMenuAbout = wxNewId();
const long BroadcastFrame::ID_STATUSBAR1 = wxNewId();
//*)

BEGIN_EVENT_TABLE(BroadcastFrame,wxFrame)
    //(*EventTable(BroadcastFrame)
    //*)
    EVT_SOCKET(UDP_SOCKET,  BroadcastFrame::OnUDPEvent)
END_EVENT_TABLE()

BroadcastFrame::BroadcastFrame(wxWindow* parent,wxWindowID id)
{
    //(*Initialize(BroadcastFrame)
    wxMenuItem* MenuItem2;
    wxMenuItem* MenuItem1;
    wxMenu* Menu1;
    wxMenuBar* MenuBar1;
    wxMenu* Menu2;

    Create(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id"));
    MenuBar1 = new wxMenuBar();
    Menu1 = new wxMenu();
    MenuItem1 = new wxMenuItem(Menu1, idMenuQuit, _("Quit\tAlt-F4"), _("Quit the application"), wxITEM_NORMAL);
    Menu1->Append(MenuItem1);
    MenuItem3 = new wxMenuItem(Menu1, idMenuSend, _("Send"), _("Send a message"), wxITEM_NORMAL);
    Menu1->Append(MenuItem3);
    MenuBar1->Append(Menu1, _("&File"));
    Menu2 = new wxMenu();
    MenuItem2 = new wxMenuItem(Menu2, idMenuAbout, _("About\tF1"), _("Show info about this application"), wxITEM_NORMAL);
    Menu2->Append(MenuItem2);
    MenuBar1->Append(Menu2, _("Help"));
    SetMenuBar(MenuBar1);
    StatusBar1 = new wxStatusBar(this, ID_STATUSBAR1, 0, _T("ID_STATUSBAR1"));
    int __wxStatusBarWidths_1[1] = { -1 };
    int __wxStatusBarStyles_1[1] = { wxSB_NORMAL };
    StatusBar1->SetFieldsCount(1,__wxStatusBarWidths_1);
    StatusBar1->SetStatusStyles(1,__wxStatusBarStyles_1);
    SetStatusBar(StatusBar1);

    Connect(idMenuQuit,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&BroadcastFrame::OnQuit);
    Connect(idMenuSend,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&BroadcastFrame::OnMenuItemSendSelected);
    Connect(idMenuAbout,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&BroadcastFrame::OnAbout);
    //*)

// Initialise the UDP datagram socket
    Init_Datagram_Socket();
}

BroadcastFrame::~BroadcastFrame()
{
    //(*Destroy(BroadcastFrame)
    //*)
}

void BroadcastFrame::OnQuit(wxCommandEvent& event)
{
    Close();
}

void BroadcastFrame::OnAbout(wxCommandEvent& event)
{
    wxString msg = wxbuildinfo(long_f);
    wxMessageBox(msg, _("Welcome to..."));
}

void BroadcastFrame::Init_Datagram_Socket()
{
// wxSocketBase::Initialize() may be necessary for wxWidgets versions
// <2.5.x, and for all versions if using secondary threads
// See https://wiki.wxwidgets.org/WxSocket
// See http://comp.soft-sys.wxwindows.narkive.com/vt9BEujR/wxsocketbase-initialize
    wxSocketBase::Initialize();

    m_LocalAddress.AnyAddress();              // Receive any address (0.0.0.0)
    m_LocalAddress.Service(MY_SERVER_PORT);   // port on which we listen

// Create the socket
    m_Listen_Socket = new wxDatagramSocket(m_LocalAddress, wxSOCKET_REUSEADDR);
    if (m_Listen_Socket->Error())
    {
        wxLogError(_("Could not open Datagram Socket\n\n"));
        return;
    }
    else
    {
///////////////////////////////////////////////////////////////////////////
// To send to a broadcast address, you must enable SO_BROADCAST socket
// option, in plain C this is:
//      int enabled = 1;
//      setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &enabled, sizeof(enabled));
// where sockfd is the socket descriptor (See http://linux.die.net/man/2/setsockopt)
// See also boxcarmiba Wed Aug 02, 2006
// at https://forums.wxwidgets.org/viewtopic.php?t=9410
        static int enabled = 1;
        m_Listen_Socket->SetOption(SOL_SOCKET, SO_BROADCAST, &enabled, sizeof(enabled) );
///////////////////////////////////////////////////////////////////////////

// Set types of event that you want to receive:
        m_Listen_Socket->SetNotify(wxSOCKET_INPUT_FLAG);
// Enable the event notification:
        m_Listen_Socket->Notify(true);
// Setup the event handler (UDP_SOCKET is our custom event ID)
// Note: Use EVT_SOCKET(UDP_SOCKET,  BroadcastFrame::OnUDPEvent) in event table
        m_Listen_Socket->SetEventHandler(*this, UDP_SOCKET);
    }
}

// Responds to an event defined by an EVT_SOCKET table entry
void BroadcastFrame::OnUDPEvent(wxSocketEvent& event)
{
#define MAX_BUF_SIZE 1024
    unsigned char buff[MAX_BUF_SIZE] = {0};
    wxSocketBase *sock = event.GetSocket();

    switch (event.GetSocketEvent())
    {
        case wxSOCKET_INPUT:
        {   // Using blocking I/O (m_Listen_Socket NOT created with wxSOCKET_NOWAIT)
            // - assumes that as an event occurred there must be data available
            sock->Read(&buff, MAX_BUF_SIZE);
            wxLogMessage(_("OnUDPEvent read: %hs\n"), buff);
            break;
        }

        default:
            wxLogMessage(_("OnUDPEvent received an unexpected event\n"));
    }   // switch
#undef MAX_BUF_SIZE
}

// Menu command to send a test UDP datagram, which should be received by this app
// and any other instances running on the local network:
void BroadcastFrame::OnMenuItemSendSelected(wxCommandEvent& event)
{
    wxString wxmessage = wxString::Format(_T("Test using port %d"), MY_SERVER_PORT);
    wxCharBuffer message = wxmessage.ToUTF8();  // used to get a const char* for SendTo

// Specify a broadcast IP, in this case "Limited Broadcast" on the local network:
    m_BroadCastAddress.Hostname(_("255.255.255.255"));
    m_BroadCastAddress.Service(MY_SERVER_PORT);

// Use same socket created for listening for sending:
    m_Listen_Socket->SendTo(m_BroadCastAddress, message.data(), strlen(message.data()));

    if (m_Listen_Socket->Error() )
    {
        wxLogMessage(_T("SendTo Error: %d"), m_Listen_Socket->LastError());
    }
}
App header:

Code: Select all

/***************************************************************
 * Name:      BroadcastApp.h
 * Purpose:   Defines Application Class
 *            wxWidgets 2.8.12 sample to send and receive a UDP broadcast datagram
 * Author:    CJS ()
 * Created:   2016-01-27
 * Copyright: CJS ()
 * License:
Excepting if sections are specifically annotated that other
conditions apply, the following MIT license shall apply:

Copyright (c) 2016 CJS
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   https://opensource.org/licenses/MIT

 **************************************************************/

#ifndef BROADCASTAPP_H
#define BROADCASTAPP_H

#include <wx/app.h>

class BroadcastApp : public wxApp
{
    public:
        virtual bool OnInit();
};

#endif // BROADCASTAPP_H
App implementation:

Code: Select all

/***************************************************************
 * Name:      BroadcastApp.cpp
 * Purpose:   Code for Application Class
 *            wxWidgets 2.8.12 sample to send and receive a UDP broadcast datagram
 * Author:    CJS ()
 * Created:   2016-01-27
 * Copyright: CJS ()
 * License:
Excepting if sections are specifically annotated that other
conditions apply, the following MIT license shall apply:

Copyright (c) 2016 CJS
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   https://opensource.org/licenses/MIT

 **************************************************************/

#include "BroadcastApp.h"

//(*AppHeaders
#include "BroadcastMain.h"
#include <wx/image.h>
//*)

IMPLEMENT_APP(BroadcastApp);

bool BroadcastApp::OnInit()
{
    //(*AppInitialize
    bool wxsOK = true;
    wxInitAllImageHandlers();
    if ( wxsOK )
    {
    	BroadcastFrame* Frame = new BroadcastFrame(0);
    	Frame->Show();
    	SetTopWindow(Frame);
    }
    //*)
    return wxsOK;

}
Edited to add attachment - includes Code::Blocks project file, rc file, and wxSmith file.
Broadcast.zip
Source code files for the wxDatagramSocket broadcast demo app
(8.65 KiB) Downloaded 458 times
Last edited by CJS on Thu Jan 28, 2016 5:14 pm, edited 1 time in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: App to demonstrate UDP broadcast datagrams using wxDatagramSocket

Post by doublemax »

Thanks. Could you add a ZIP file with all four source files? That would make it easier for anyone who wants to try it out.
Use the source, Luke!
vixivtech
In need of some credit
In need of some credit
Posts: 1
Joined: Fri Feb 03, 2017 2:17 am

Re: App to demonstrate UDP broadcast datagrams using wxDatagramSocket

Post by vixivtech »

I can get this to compile on Linux 4.8.0 with wxWidgets 3.1.0 (Latest as of this writing). Zero errors and warnings compiling with Codelite 9.2.0.
Upon Execution I do receive some warnings which apparently used to result in fatal error:

20:48:44: Warning: Mismatch between the program and library build versions detected.
The library used 3.0 (wchar_t,compiler with C++ ABI 1009,wx containers,compatible with 2.8),
and your program used 3.0 (wchar_t,compiler with C++ ABI 1010,wx containers,compatible with 2.8).

https://bbs.archlinux.org/viewtopic.php ... 6#p1524176

Using wireshark and etherape I can see that the broadcast is successfully being sent, but I am not receiving the response and can not tell if the program is receiving the event through your:

BEGIN_EVENT_TABLE(BroadcastFrame,wxFrame)
//(*EventTable(BroadcastFrame)
//*)
EVT_SOCKET(UDP_SOCKET, BroadcastFrame::OnUDPEvent)
END_EVENT_TABLE()

Any suggestions?
Post Reply