PDA

View Full Version : QUdpSocket binding doesn't work



bhuff70
24th March 2009, 16:23
I have looked at your documentation about QUdpSocket as well as your code snippet.

According to the snippet, once I call bind() and connect readRead() I should be able to receive datagrams.

I have written a test program which attempts to do this. I can only get a response if I call connectToHost(). Your documentation says that I shouldn't do this. When I apply connectToHost() and disconnectFromHost() repititively, I get a memory leak.

So why does connectToHost() work and bind() doesn't work. I am working with v4.5 on Windows XP.

Thanks,

bhuff

bhuff70
24th March 2009, 20:43
The bind() only works if I am not specifying an IP address. If I specify QHostAddress:Any with a port it works. Is this a bug? What good is it if I can't specify an IP address?

wysota
24th March 2009, 20:45
In what way does bind() not work? What does hasPendingDatagrams() return on the receiving side after you transmit the datagram from the sender?

bhuff70
24th March 2009, 20:48
No readyRead() signal is triggered. I am following the snippet closely in my test code. I can only get it to work with bind(QHostAddress::Any,port). Any specific IP address, it doesn't work.

wysota
24th March 2009, 21:41
AFAIK ReadyRead() will not be triggered without connectToHost().

bhuff70
25th March 2009, 13:28
From the documentation, connectToHost() was used with write() and read() which are methods from QIODevice. So you mean that even if I use readDatagram() and writeDatagram(), I must still use connectToHost()? What is the purpose of using bind()?
From my own experiments, bind() seems to do very little. The documentation says that bind() is used instead of connectToHost(). Is the documentation wrong? Maybe I am not understanding it correctly.

wysota
25th March 2009, 22:48
So you mean that even if I use readDatagram() and writeDatagram(), I must still use connectToHost()?
No, I mean you will not receive readyRead() signals.


What is the purpose of using bind()?
You give address to the socket. Without it it wouldn't be possible to send anything to your socket.


From my own experiments, bind() seems to do very little. The documentation says that bind() is used instead of connectToHost(). Is the documentation wrong? Maybe I am not understanding it correctly.

It all becomes clear once you understand how UDP works and how ::bind and ::connect() work. UDP is connectionless protocol therefore with a single socket you can reach multiple targets and receive data from multiple sources. ::bind (and QUdpSocket::bind()) associates an address (interface and UDP port) with your (local) socket. Since this moment you can start receiving data on the socket because the operating system knows that if data reaches a specific UDP port on a specific network interface, it should be forwarded to your socket.

As UDP is a connectionless protocol it is obvious that ::connect() (and QAbstractSocket::connectToHost()) doesn't do any connecting. In particular no data gets exchanged in the network. All it does is that it associates your socket with a default remote address. Thanks to that you don't have to pass the peer address to functions for receiving or sending a datagram - instead the address you passed to ::connect() will be used. You can still receive datagrams from other addresses and you can still send datagrams to other addresses. The only difference is that you will have to specify peer addresses while sending or receiving if you don't call ::connect().

bhuff70
27th March 2009, 15:57
Thanks for trying to explain this. You are saying that using connectToHost() establishes a default address for the socket. Then is bind() used to switch to a different address without calling connectToHost() for that address?

From my projects, I found that I must use connectToHost() to get the socket sending/receiving somewhere. I don't use bind() at all. I understand the connectionless nature of UDP and that connectToHost() is something done on that socket end only.

wysota
27th March 2009, 17:23
bind() establishes the address of the local end of communication, connectToHost() establishes the address of the remote end of communication. I can't explain it more clearly :) Oh, and bind() is not used to switch anything, until you don't bind your socket, you won't be able to do pretty much anything with the socket and I think once a socket is bound, it can't be rebound to another address - you'd have to close the socket and bind it again (or even create a new one first).

Maybe the fact that you don't receive the readyRead() signal is caused by not using bind in the first place. The example in QUdpSocket clearly indicates you should do that and what connectToHost is meant for.

bhuff70
27th March 2009, 18:45
I got my test to work WITHOUT using bind(). I couldn't get it to work without using connectToHost().

It is still not clear what bind() is for. Is bind() used to define an IP address/socket on the socket's end? Is that what you mean?

wysota
27th March 2009, 18:49
You know what? I really hate repeating myself all the time. Qt is Open Source, just take the sources and see for yourself.

bhuff70
27th March 2009, 20:02
I was hoping to get an answer without looking at the source code. But thanks for your help anyway.

wysota
27th March 2009, 21:57
You have received the answer two times. Yet you failed to see it. Repeating it the third time won't help much.

MrAdaMrAda
5th February 2013, 14:24
This article is very helpful. I am having a situation where we didn't use the connect to host function. I have a situation where our client SW is listening for a response from our server. I know the server was enunciating a response. I had to send a dummy command out from the client to, in a sense, activate the port to allow my client to accept server responses! I am going to try this connect to host for sure to see if it makes a difference which I suspect it will. Thank you.

chris

MrAdaMrAda
5th February 2013, 17:21
Dang! That didn't work. I only put the code on the client side, now I am wondering if I need connectToHost on the server side too.

ChrisW67
5th February 2013, 22:54
You only need to use QUdpSocket::connectToHost() to set a default remote end if you are using the standard QIODevice interface (read(), readLine(), write()) because these functions do not supply an address/port. If you are using only readDatagram() then only a call to bind() is required. You can send with writeDatagram() without using bind().

If you had to "send a dummy command out from the client" then its possible you have a firewall between your sender and receiver and that this is not a Qt issue.

EdLaFave
5th April 2014, 20:56
bhuff70, I struggled with a very similar problem today and it took a couple reads and a bit of experimentation to understand wysota's posts but it is now clear to me. Perhaps an explanation from a slightly different perspective will help you. In my case there was a pre-existing UDP server that does the following:

-Receives a UDP packet.
-Extracts the Address and Port tuple from the incoming packet.
-Does some processing.
-Sends a UDP packet to the extracted Address and Port tuple.

I simply needed to write a "client" that would send a UDP packet to the server and receive the response. Below was my first attempt to solve this problem and the end result was that the server received the UDP packet from my client but my client never received the response:


connect(&mUdpSocket, SIGNAL(readyRead()), this, SLOT(handleResponse()));
mUdpSocket.writeDatagram(messageByteArray, severAddress, serverPort);

I know for a fact that the server sent a response to the Address/Port tuple it extracted from the UDP packet my client sent. Additionally, I know the Address/Port tuple had reasonable values implying they were implicitly set by the QUdpSocket. I made what appears to be the false assumption that the QUdpSocket would automatically be associated with that same Address/Port tuple and therefore receive the response packet from the server.

So the big question seemed to be how to "bind" my QUdpSocket to the Address/Port that is getting set on the UDP packet. That is where the bind method comes into play. I made the following slight change to my code and I was suddenly receiving responses from the server:


connect(&mUdpSocket, SIGNAL(readyRead()), this, SLOT(handleResponse()));
mUdpSocket.bind();
mUdpSocket.writeDatagram(messageByteArray, severAddress, serverPort);

Calling the bind method links the socket to an Address/Port tuple. When you call the writeDatagram method it sends a UDP packet that contains that very same tuple. My server extracts that tuple from the incoming UDP packet and sends a response packet addressed to the tuple. Since my socket is bound to the tuple it then is able to receive the response. The readyRead signal will ONLY fire if you've called the bind method.

Many of the things mentioned in this thread appear to be true. The connectToHost method has an association with read and write. Similarly the bind method has an association with writeDatagram, readDataGram, and readyRead. It seems you can pick either route you want to use to transfer data...that is to say if you're using connectToHost/read/write then you don't have to use bind/writeDatagram/readDatagram/readyRead and vice versa.