QUdpSocket not working without bind

3.3k views Asked by At

I have to communicate with some device over UDP. The problem is that QUdpSocket doesn't not work at all without special case of bind(). I use the connectToHost() method for access to read()/write() functions.

UDP exchange not working at all when using the code:

m_udp.connectToHost(QHostAddress("192.168.100.15"), 4001);    
m_udp.waitForConnected();

The I don't receive any bytes. Message in Wireshark:

QUdpSocket error in Wireshark

The below code doesn't work too:

m_udp.bind(QHostAddress("192.168.100.15"), 4001);
m_udp.connectToHost(QHostAddress("192.168.100.15"), 4001);    
m_udp.waitForConnected();

Only this code works:

m_udp.bind(4001);
m_udp.connectToHost(QHostAddress("192.168.100.15"), 4001);    
m_udp.waitForConnected();

But the code works only in Qt 5.6.2 and not work in Qt 5.4.2. Here is how I try to receive:

dev->waitForReadyRead(500);
QByteArray ba = dev->readAll();

Why the behaviour is so strange? How can one understand this?

2

There are 2 answers

0
Gil Hamilton On

You haven't shown the code for the other side, but apparently from the wireshark image shown, the remote peer is expecting your socket to be bound to port 4001.

The first code snippet attempts to connect to the (RemoteAddress, 4001) without specifying a local port (hence the kernel assigns an arbitrary port number (64875 according to wireshark) but as mentioned above, the other side is expecting to send back to port 4001. Hence you can't receive it on port 64875.

In UDP, there is no such thing as an actual connection. When you use connectToHost you're really only specifying the remote side's IP address and port number. It is the application's responsibility to make sure the remote side sends back to the correct port. That can be done by (a) always sending to a particular port (as is apparently being done here), or (b) the other side can look at the address/port from which the datagram is actually received and send back to that; in other words, the remote side could determine that the datagram it received had been sent from port 64875 and target its reply to that port.

In the second try, you're attempting to bind your local endpoint to an address on the other machine which simply doesn't make any sense. (I'm guessing this snippet would work if you changed the bind to m_udp.bind(QHostAddress("192.168.100.3"), 4001); -- your local machine's IP address.)

Only the third snippet works because here you're binding to local port 4001 without specifying an IP address, then also sending to port 4001 on the remote machine. If you specify only the port number in the bind, then the IP address will be left as "wildcard" and hence you should get packets sent to that port number on any of your machine's IP addresses.

(No idea why you would be seeing different behavior in an earlier version of Qt.)

0
ringul On

Check the state of the socket after binding before even writing or reading.

See this code:

QHostAddress serverIP("172.168.1.100");
if(socket->bind(serverIP,port,QUdpSocket::ShareAddress)) //even if local Host dont have static IP( on subnet expected 172.168.x.x),still it becomes true and enters if.
    {
    if( (socket->state() == QAbstractSocket::BoundState) && (((socket->localAddress()).protocol()) == QAbstractSocket::IPv4Protocol) ) //ignore protocol validation if not required.
        {

         }
 else
        {
            qDebug()<<"Socket not in bound state. address is: "<<QHostAddress::LocalHost<<" and the port "<<port;
            //Return = false;
        }
    }
else
    {
        qDebug()<<"Failed to bind socket to the address "<<QHostAddress::LocalHost<<" and the port "<<port;
        //Return = false;
    }

Secondly, sockets in Qt will emit error signals if some thing goes wrong. So you should have a slot to catch those error signals. This way you can know the reason behind the issue.

for Example:

connect(udpsocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(onSocketError(QAbstractSocket::SocketError)));

Slot to receive socker errors:

void SomeInterface::onSocketError(QAbstractSocket::SocketError socketError)
{
    qDebug()<<"socket error occured and the error is : "<<socketError;
}