Eos Pengwern
8th November 2010, 14:28
As the title suggests, I'm trying to use a QUdpSocket to detect a peripheral which is attached to the host computer. The desired sequence-of-events is:
1. Host broadcasts an "Is anybody there" message to its whole network.
2. The peripheral, on receiving the broadcast, sends a message back saying "here I am".
3. The host receives the response, and checks whether it is a valid "here I am" message; if not, it ignores it and waits for the next message; if it is, then it makes a notes of the sender's address so further communications can be addressed exclusively to the peripheral.
Here's my code:
// The QByteArray "datagram" initially contains the "Is anybody there" message
QUdpSocket udpSocket;
udpSocket.bind(QHostAddress::Any, 2101);
udpSocket.writeDatagram(datagram.data(), datagram.size(),
QHostAddress::Broadcast, 2101);
datagram.resize(sizeof(DISCOVERY_RESPONSE));
QHostAddress senderAddress;
quint16 senderPort;
QTime timeout_counter;
timeout_counter.start();
while (timeout_counter.elapsed() < TIMEOUT)
{
if (udpSocket.hasPendingDatagrams())
{
int returnedSize = udpSocket.readDatagram(datagram.data(), datagram.size(),
&senderAddress, &senderPort);
int responseSize = sizeof(DISCOVERY_RESPONSE);
if (returnedSize == responseSize)
{
// Great joy
DISCOVERY_RESPONSE *response = reinterpret_cast<DISCOVERY_RESPONSE *>(datagram.data());
}
}
else QCoreApplication::processEvents();
}
What actually happens is that the "udpSocket.readDatagram" line immediately receives the host's own broadcast but, realising that this isn't what its looking for, discards it and carries on listening. The remote peripheral, meanwhile, receives the broadcast and responds to it. However, the QUdpSocket does not received the response, it just carries on looping till it times out.
If I happen to know the peripheral's IP address already (for example, by interrogating my router) and I hard-code this addess in place of QHostAddress::Broadcast in the above code, then everything behaves perfectly. It's as if, having once received data from one address (i.e. its own broadcast), the QUdpSocket has become blind to data sent from anywhere else, despit having been bound at the beginning to QHostAddress::Any. Is there a way that I can reset it, or is there something else that I'm doing wrong here?
Thanks,
Stephen.
Added after 8 minutes:
How odd...
If I disable my firewall, then it works properly. Yet even with the firewall in place, the broadcast message got out to the peripheral, and the message from the peripheral was getting back whenever it had been addressed directly as opposed to being addressed via a broadcast.
It's as if the firewall shuts down incoming messages whenever it detects that a broadcast has taken place. Very antisocial.
So, today I've learned nothing about QUdpSockets but plenty about Firewalls.
Stephen.
1. Host broadcasts an "Is anybody there" message to its whole network.
2. The peripheral, on receiving the broadcast, sends a message back saying "here I am".
3. The host receives the response, and checks whether it is a valid "here I am" message; if not, it ignores it and waits for the next message; if it is, then it makes a notes of the sender's address so further communications can be addressed exclusively to the peripheral.
Here's my code:
// The QByteArray "datagram" initially contains the "Is anybody there" message
QUdpSocket udpSocket;
udpSocket.bind(QHostAddress::Any, 2101);
udpSocket.writeDatagram(datagram.data(), datagram.size(),
QHostAddress::Broadcast, 2101);
datagram.resize(sizeof(DISCOVERY_RESPONSE));
QHostAddress senderAddress;
quint16 senderPort;
QTime timeout_counter;
timeout_counter.start();
while (timeout_counter.elapsed() < TIMEOUT)
{
if (udpSocket.hasPendingDatagrams())
{
int returnedSize = udpSocket.readDatagram(datagram.data(), datagram.size(),
&senderAddress, &senderPort);
int responseSize = sizeof(DISCOVERY_RESPONSE);
if (returnedSize == responseSize)
{
// Great joy
DISCOVERY_RESPONSE *response = reinterpret_cast<DISCOVERY_RESPONSE *>(datagram.data());
}
}
else QCoreApplication::processEvents();
}
What actually happens is that the "udpSocket.readDatagram" line immediately receives the host's own broadcast but, realising that this isn't what its looking for, discards it and carries on listening. The remote peripheral, meanwhile, receives the broadcast and responds to it. However, the QUdpSocket does not received the response, it just carries on looping till it times out.
If I happen to know the peripheral's IP address already (for example, by interrogating my router) and I hard-code this addess in place of QHostAddress::Broadcast in the above code, then everything behaves perfectly. It's as if, having once received data from one address (i.e. its own broadcast), the QUdpSocket has become blind to data sent from anywhere else, despit having been bound at the beginning to QHostAddress::Any. Is there a way that I can reset it, or is there something else that I'm doing wrong here?
Thanks,
Stephen.
Added after 8 minutes:
How odd...
If I disable my firewall, then it works properly. Yet even with the firewall in place, the broadcast message got out to the peripheral, and the message from the peripheral was getting back whenever it had been addressed directly as opposed to being addressed via a broadcast.
It's as if the firewall shuts down incoming messages whenever it detects that a broadcast has taken place. Very antisocial.
So, today I've learned nothing about QUdpSockets but plenty about Firewalls.
Stephen.