Multicast Issue, possible bug?
-
Hey guys.
I'm having some issues with multicast. I've backtraced all the way to the examples (here and here)
It seems that I cannot set TTL before the first write to the socket. But setting it after the first write works fine. My current setup requires TTL >= 2 for the packages to be delivered, that's how I bumped into this.
Setup: Start receiver example on PC1, start sender example on PC2. PC1 displays 'Listening for multicast messages' and PC2 displays the sender GUI.
Test case:
-
Perform Setup (above)
-
Change the TTL box to '2'
-
Press 'Start'
-
No data is received.
-
Change TTL box to '3' then back to '2'
-
Data is received.
So, setting TTL seems to have no effect unless there has been a single write to the socket before. This had me pulling my hair for some time. Is this a feature or a bug? Or am I simply missing something?
EDIT: PC1 (Receiver) uses Qt 5.7 on Windows 10 64b it. PC2 (Sender) uses Qt 5.3.2 on debian 64 bit inside a virtual machine.
-
-
@kshegunov said in Multicast Issue, possible bug?:
Could you try setting it to a TCP socket?
For multicast you have to stick to UDP...
-
@JohanSolo said in Multicast Issue, possible bug?:
For multicast you have to stick to UDP...
I know that, I meant for any regular TCP socket connection.
-
@BjornW said in Multicast Issue, possible bug?:
How to set TTL on a tcp socket, though?
On linux use setsockopt and setsockopt on windows. The option name is IP_MULTICAST_TTL on both platforms
-
Remember that this is the Qt forums :D. I'm dealing with QTcpSocket/QUdpSocket
I do set set QAbstractSocket::MulticastTtlOption (Which should correspond to IP_MULTICAST_TTL). But I don't see whats that does for a TCP socket.
QAbstractSocket::MulticastTtlOption - Set this to an integer value to set IP_MULTICAST_TTL (TTL for multicast datagrams) socket option.
-
@BjornW said in Multicast Issue, possible bug?:
Remember that this is the Qt forums :D. I'm dealing with QTcpSocket/QUdpSocket
My bad... sorry!
According to wikipedia, TTL for UDP and TCP simply defines the number of subnets the packet is allowed to travel through: "The TTL field is set by the sender of the datagram, and reduced by every router on the route to its destination. If the TTL field reaches zero before the datagram arrives at its destination, then the datagram is discarded and an ICMP error datagram (11 - Time Exceeded) is sent back to the sender."
-
Yes that is correct. The issue is that the following does not work when TTL >= 2 is needed:
udpSocket = new QUdpSocket(this); udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 2) udpSocket->writeDatagram(someData, someAddress, somePort)
but the following DOES work:
udpSocket = new QUdpSocket(this); udpSocket->writeDatagram(QByteArray(), QHostAddress(), 0) udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 2) udpSocket->writeDatagram(someData, someAddress, somePort)
Seems unintended.
-
@BjornW said in Multicast Issue, possible bug?:
udpSocket = new QUdpSocket(this); udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 2) udpSocket->writeDatagram(someData, someAddress, somePort)
As I noted you should try binding the socket first. I.e. call
bind()
after the constructor. E.g.udpSocket = new QUdpSocket(this); udpSocket->bind(); udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 2);
My suspicion is that this call fails silently if you don't. Sending an empty datagram should call
bind()
and initialize the socket for you, but I can't see the flags applied in the deferred initialization code, namely here. -
I will try that when I get back home.
I was under the impression that bind() is used when listening to a socket, but then I'm relatively new to network programming.
The multicast sender example does not use bind.
From the docs
For UDP sockets, after binding, the signal QUdpSocket::readyRead() is emitted whenever a UDP datagram arrives on the specified address and port. Thus, This function is useful to write UDP servers.
No mention that it is required for sending or a client.
-
@BjornW said in Multicast Issue, possible bug?:
I was under the impression that bind() is used when listening to a socket, but then I'm relatively new to network programming.
The multicast sender example does not use bind.No, bind is needed. In any case
writeDatagram()
will bind the socket for you (internally). The problem I see is that Qt's code doesn't apply the flags after the socket is initialized. I may be completely off, but I'd say it's a minor bug. On a related note, does the example code set the TTL properly, as I really don't see any significant difference from your code? -
I'll describe what happens in my original test case
- Start the applications // <-- No 'bind' is called anywhere in the sender code
- Change the TTL box to '2' //<-- the ttlChanged slot is invoked where udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 2); is called.
- Press 'Start'
- Data i sent but no data is received //<-- Because 1: My system setup requires TTL >= 2 for data to reach destination and 2: the previous setting of MulticastTtlOption has not been applied properly
- Change TTL box to '3' then back to '2' // <-- once again, the ttlChanged slot is invoked and the setSocketOption method is called. This time, writeDatagram has been called multiple times already (implicitly calling bind()?)
- Data is sent and is now also received properly