Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Multicast Sender / Receiver on different computers

Multicast Sender / Receiver on different computers

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 2 Posters 2.9k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • bigguinessB Offline
    bigguinessB Offline
    bigguiness
    wrote on last edited by
    #1

    Hello all,

    Not sure if this has been covered but I can't find any information about it.

    I am trying to multicast from one PC to another PC (on the same network).

    I'm using these multicast examples:
    https://code.qt.io/cgit/qt/qtbase.git/tree/examples/network/multicastsender?h=6.3
    https://code.qt.io/cgit/qt/qtbase.git/tree/examples/network/multicastreceiver?h=6.3

    If I run the sender and receiver on the same PC it works fine.

    But if I run the sender on one PC and the receiver on another, the receiver never gets anything. It does not matter which PC I run the sender on, the receiver on the other PC never gets the message.

    I have an old Windows Visual Studio program that does something similar and it works with no problems. I'm in the process of updating that code to use Qt instead but can't get this part to work.

    What am I missing?

    Thanks

    1 Reply Last reply
    0
    • M Offline
      M Offline
      mchinand
      wrote on last edited by
      #2

      You should make sure that any routers and/or switches between the two computer pass along multicast packets. You can run Wireshark on the receiving computer to see if the packets are getting to it.

      1 Reply Last reply
      0
      • bigguinessB Offline
        bigguinessB Offline
        bigguiness
        wrote on last edited by
        #3

        Hello,

        I have tried running Wireshark.

        Some additional information.

        My laptop has multiple network interfaces. Specifically, this code:

        QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
        foreach (QNetworkInterface iface, list) {
            qDebug() << "Interface:" << iface.humanReadableName();
        }
        

        Give me this result on the 1st PC:

        Interface: "Ethernet"
        Interface: "VirtualBox Host-Only Network"
        Interface: "Ethernet 2"
        Interface: "Wi-Fi"
        Interface: "Local Area Connection* 1"
        Interface: "Local Area Connection* 2"
        Interface: "Bluetooth Network Connection"
        Interface: "Loopback Pseudo-Interface 1"

        When I run the sender / receiver on that PC, I am only seeing the multicast messages with WireShark on the "VirtualBox Host-Only Network" interface.

        The other PC is running Ubuntu and has these interfaces:

        Interface: "eno1"
        Interface: "wlp0s20f3"

        When I run the sender / receiver on that PC I get the multicast messages on the "wlp0s20f3" interface which is connected to the "Ethernet" interface on the 1st PC.

        So it looks like the problem may be that the 1st PC is not binding the sender to the correct interface. Is there a way to force it?

        I really want the sender to send the message on all interfaces and the receiver to catch those messages.

        I thought the Windows code was confusing but at least it worked....

        Thanks

        1 Reply Last reply
        0
        • bigguinessB Offline
          bigguinessB Offline
          bigguiness
          wrote on last edited by
          #4

          I may have found a solution, just not sure if it's correct.

          I changed the code in the receive from this:

          udpSocketRx.bind(QHostAddress::AnyIPv4, RX_PORT, QUdpSocket::ShareAddress);
          udpSocketRx.joinMulticastGroup(groupAddress);
          

          to this:

          udpSocketRx.bind(QHostAddress::AnyIPv4, RX_PORT, QUdpSocket::ShareAddress);
          QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
          foreach (QNetworkInterface iface, list)
              udpSocketRx.joinMulticastGroup(groupAddress, iface);
          

          Now both receivers get the messages from both senders.

          Strangely no change was needed in the sender code.

          1 Reply Last reply
          0
          • bigguinessB Offline
            bigguinessB Offline
            bigguiness
            wrote on last edited by
            #5

            OK, not quite fixed.

            The sender / receiver is working on my 1st PC "Ethernet" / 2nd PC "wlp0s20f3" interface (10.168.0.xxx network).

            But it I try to start a sender / receiver on my 2st PC "Ethernet 2" / some other PC interface (192.168.100.xxx network) it does not work.

            1. Running the sender, WireShark only shows it joining the group on the "Ethernet" interface.

            2. Running the receiver, WireShark only shows it joining the group on the "Ethernet 2" interface.

            3. Starting the sender, WireShark only shows the send/receive messages on the "Ethernet" interface.

            4. Running the receiver first, WireShark shows it joining the group on both the "Ethernet" and "Ethernet 2" interface.

            5. Running the sender, WireShark does not show any joining of the group.

            6. Starting the sender, WireShark only shows the send/receive messages on the "Ethernet" interface.

            As a sanity check, I checked my old Windows code.

            1. Run the "receiver" first, WireShark shows it joining the group on the "Ethernet 2" interface.
            2. Run the "sender", WireShark shows it joining the group on both the "Ethernet" and "Ethernet 2" interface
            3. WireShark shows the send messages on both the "Ethernet" and "Ethernet 2" interfaces.
            4. WireShark shows the receive messages on the "Ethernet 2" interface.

            Running the "sender" then the "receiver" also works.

            Also, connecting another "receiver" on the "Ethernet" interface works. I get receive messages from both "Ethernet" and "Ethernet 2" interfaces.

            Note, I am expecting messages in both directions. The sender is actually sending a query message as a multicast on a given port. All attached receivers then send a reply message on a different port.

            My modified code based on the Qt Multicast Sender / Receiver example does the send query / receive response just fine. But only ON the "Ethernet" interface. I need it to work on all connected interfaces.

            Any help is appreciated.

            1 Reply Last reply
            0
            • bigguinessB Offline
              bigguinessB Offline
              bigguiness
              wrote on last edited by
              #6

              I'm still not getting this. :-(

              Some background may help.

              1. My host machine can have multiple network interfaces (and it does).
              2. I have one or more "target" devices connected to my network. They could be connected to any interface of my host machine.
              3. The target device listens on port 13020 for multicast "query" commands
              4. The target device responds on port 13021 with a "reply" message that contains it's IP address and ID information.
              5. The host machine runs this "sender" app to send the query commands on all interfaces. It then receives the "reply" messages from all the targets and processes them.

              This works kind of like a network printer discovery.

              Currently my setup of the sender QUdpSocket send/receive looks like this:

              #define TX_PORT 13020   // host query transmit / target query receive port
              #define RX_PORT 13021   // host reply receive / target transmit reply port
              
              Sender::Sender(QWidget* parent)
                  : QDialog(parent),
                    groupAddress(QStringLiteral("226.13.13.13")) {
              
                  QUdpSocket::BindMode flags = QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint;
                  udpSocketTx.bind(TX_PORT, flags);
              
                  udpSocketRx.bind(QHostAddress::AnyIPv4, RX_PORT, flags);
                  QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
                  foreach (QNetworkInterface iface, list) {
                      if (iface.flags().testFlag(QNetworkInterface::IsRunning) &&
                          iface.flags().testFlag(QNetworkInterface::CanMulticast) &&
                          !iface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
                          if (udpSocketRx.joinMulticastGroup(groupAddress, iface))
                              qDebug() << iface.index() << iface.humanReadableName() << "joined multicast" << groupAddress;
                      }
                  }
              
                  // setup the GUI
                  ...
              
                  // connect the signal/slots
                  ...
                  connect(&udpSocketRx, &QUdpSocket::readyRead, this, &Sender::processPendingDatagrams);
              }
              

              The qDebug() output on my test machine is:

              4 "Ethernet" joined multicast QHostAddress("226.13.13.13")
              7 "VirtualBox Host-Only Network" joined multicast QHostAddress("226.13.13.13")
              20 "Ethernet 2" joined multicast QHostAddress("226.13.13.13")
              

              I'm only interested in the "Ethernet" and "Ethernet 2" interfaces. In WireShark I see both of them joining the multicast group:

              190499	6861.248925	10.168.0.95	224.0.0.22	IGMPv3	54	Membership Report / Join group 226.13.13.13 for any sources
              105338	6836.393405	192.168.100.100	224.0.0.22	IGMPv3	54	Membership Report / Join group 226.13.13.13 for any sources
              

              When I start the sender I see the messages on the "Ethernet 2" interface:

              105339	6836.393443	192.168.100.100	226.13.13.13	UDP	78	13020 → 13020 Len=36
              

              But the sender messages do not show up on the "Ethernet" interface.

              I do see the reply messages on the "Ethernet 2" interface:

              105340	6836.393954	192.168.100.101	226.13.13.13	UDP	302	13021 → 13021 Len=260
              

              But the readyRead signal is never generated so processPendingDatagrams() is never called.

              I don't see any reply messages on the "Ethernet" interface due to the query messages never getting sent on that interface.

              I did find something about using QNetworkDatagram::setInterfaceIndex() to select the interface that QUdpSocket::writedatagram() sends the datagram on. I modified my sendDatagram() method to use that but still only see the message on the "Ethernet 2" interface:

              void Sender::sendDatagram() {
                  QByteArray data = "? Query " + QByteArray::number(messageNo);
                  QNetworkDatagram datagram(data, groupAddress, TX_PORT);
                  QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
                  foreach (QNetworkInterface iface, list) {
                      if (iface.flags().testFlag(QNetworkInterface::IsRunning) &&
                          iface.flags().testFlag(QNetworkInterface::CanMulticast) &&
                          !iface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
                          uint index = iface.index();
                          datagram.setInterfaceIndex(index);
                          udpSocketTx.writeDatagram(datagram);
                          qDebug() << index << datagram.interfaceIndex() << iface.humanReadableName();
                      }
                  }
                  qDebug() << data;
                  ++messageNo;
              }
              

              The qDebug() output is:

              4 4 "Ethernet"
              7 7 "VirtualBox Host-Only Network"
              20 20 "Ethernet 2"
              "? Query 1"
              

              So I have at least two problems still.

              • The "query" messages are not being sent on all interfaces.
              • The "reply" messages are not correctly being received (no readyRead signal generated).

              Any help would be greatly appreciated.

              1 Reply Last reply
              0
              • bigguinessB Offline
                bigguinessB Offline
                bigguiness
                wrote on last edited by
                #7

                OK. This is super annoying....

                I have been trying to so this with Qt 5.12.4 since that is what I am most familiar with.

                I just recompiled the same code with Qt 6.2.1 and it works.

                I have spent the last week or more trying to get this to work.

                Is this a known BUG with multicasting in Qt 5.12.4? Is there any way around it?

                Regards

                1 Reply Last reply
                0
                • bigguinessB Offline
                  bigguinessB Offline
                  bigguiness
                  wrote on last edited by
                  #8

                  Now I'm really getting annoyed!

                  I have the stand-alone "sender" now working. It sends the query datagrams on all the interfaces on port 13020. Any target devices get that query datagram and respond with a reply datagram on the multicast port 13021. My "sender" receives those replies and handles them appropriately. Great!

                  I copied the QUdpSocket setup code from my stand-alone "sender" to my real application. I also copied the methods that send and receive the datagrams.

                  But my real application is only sending the query datagrams. I see the replies in WireShark but my application never generates the QUdpSocket::readyRead signal and I never receive the reply datagrams.

                  As far as I can tell everything is the same. Both are using Qt 6.2.1 and the socket stuff is identical. Ugh....

                  Good thing it's the end of the day. I'm about ready to toss Qt and just deal with Visual Studio and it's stupidness....

                  Maybe tomorrow I'll figure it out. Not getting much insight here....

                  Regards

                  1 Reply Last reply
                  0
                  • bigguinessB Offline
                    bigguinessB Offline
                    bigguiness
                    wrote on last edited by
                    #9

                    I'm really stuck here. Any insight would really be appreciated.

                    Like I said above, my stand-alone app is working perfectly. But when I try to do it in my real app I never receive the reply datagrams (no QUdpSocket::readyRead signals).

                    My constructor in both creates a QList of all the interface transmit socket and a QList of all the interface receive sockets and joins them to the multicast group:

                        QUdpSocket::BindMode flags = QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint;
                    
                        // Create tx/rx sockets for all capable interfaces and join rx sockets to multicast group
                        QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
                        foreach (QNetworkInterface iface, list) {
                            if (iface.flags().testFlag(QNetworkInterface::IsRunning) &&
                                iface.flags().testFlag(QNetworkInterface::CanMulticast) &&
                                !iface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
                    
                                QList<QNetworkAddressEntry> entries = iface.addressEntries();
                                foreach (QNetworkAddressEntry entry, entries) {
                                    if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                                        QUdpSocket* socket = new QUdpSocket;
                                        socket->bind(QHostAddress(entry.ip()), MULTICAST_TX_PORT, flags);
                                        txSockets.append(socket);
                    
                                        socket = new QUdpSocket;
                                        socket->bind(QHostAddress::AnyIPv4, MULTICAST_RX_PORT, flags);
                                        socket->joinMulticastGroup(groupAddress, iface);
                                        connect(socket, &QUdpSocket::readyRead, this, &Sender::processPendingDatagrams);
                                        rxSockets.append(socket);
                    
                                        qDebug() << iface.humanReadableName() << entry.ip() << "joined multicast group" << groupAddress;
                                    }
                                }
                            }
                        }
                    

                    The "query" commands are then set on all the transmit sockets (once every second):

                        QByteArray data = "? Query " + QByteArray::number(messageNo);
                        foreach (QUdpSocket* socket, txSockets)
                            socket->writeDatagram(data, groupAddress, MULTICAST_TX_PORT);
                        ++messageNo;
                    

                    The QUdpSocket::readyRead signal then reads all the receive sockets for pending replies:

                        QByteArray datagram;
                        foreach (QUdpSocket* socket, rxSockets) {
                            while (socket->hasPendingDatagrams()) {
                                int sz = socket->pendingDatagramSize();
                                datagram.resize(sz);
                                socket->readDatagram(datagram.data(), datagram.size());
                                if (sz == sizeof(discovery)) {
                                    memcpy((void*)&discovery, datagram.constData(), sz);
                                    // handle the discovery response
                                }
                            }
                        }
                    

                    The only difference between the stand-alone app and my real app is how the QDialog widgets are constructed.
                    The stand-alone app creates all the widgets manually, like the example code.
                    My real app uses a ui file.

                    Any ideas?

                    1 Reply Last reply
                    0
                    • bigguinessB Offline
                      bigguinessB Offline
                      bigguiness
                      wrote on last edited by
                      #10

                      Ugh... Windows is so frustrating...

                      Ended up being a firewall issue on my app. I allowed it on the first run but Windows only allowed it on the "Public" network. I had to allow it on the "Domain" and "Private" networks for some reason.

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved