QUdpSocket не работает без привязки

Я должен общаться с некоторым устройством через UDP. Проблема в том, что QUdpSocket не работает вообще без особого случая bind (). Я использую метод connectToHost() для доступа к функциям read()/write().

UDP-обмен вообще не работает при использовании кода:

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

Я не получаю никаких байтов. Сообщение в Wireshark:

Ошибка QUdpSocket в Wireshark

Код ниже тоже не работает:

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

Только этот код работает:

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

Но код работает только в Qt 5.6.2 и не работает в Qt 5.4.2. Вот как я пытаюсь получить:

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

Почему поведение так странно? Как можно это понять?

2 ответа

Вы не показали код для другой стороны, но, как видно из показанного изображения wireshark, удаленный узел ожидает, что ваш сокет будет связан с портом 4001.

Первый фрагмент кода пытается подключиться к (RemoteAddress, 4001) без указания локального порта (следовательно, ядро ​​назначает произвольный номер порта (64875 в соответствии с wireshark), но, как упоминалось выше, другая сторона ожидает отправки обратно на порт 4001 Следовательно, вы не можете получить его через порт 64875.

В UDP нет такой вещи, как фактическое соединение. Когда вы используете connectToHost вы действительно указываете только IP-адрес и номер порта удаленной стороны. Приложение несет ответственность за то, чтобы удаленная сторона отправляла обратно на правильный порт. Это может быть сделано путем (а) всегда отправки на конкретный порт (как это, очевидно, делается здесь) или (б) другая сторона может посмотреть на адрес / порт, с которого дейтаграмма фактически получена, и отправить обратно на него; другими словами, удаленная сторона может определить, что полученная датаграмма была отправлена ​​с порта 64875, и направить свой ответ на этот порт.

Во второй попытке вы пытаетесь привязать свою локальную конечную точку к адресу на другом компьютере, который просто не имеет никакого смысла. (Я предполагаю, что этот фрагмент будет работать, если вы изменили привязку к m_udp.bind(QHostAddress("192.168.100.3"), 4001); - IP-адрес вашей локальной машины.)

Работает только третий фрагмент, потому что здесь вы привязываетесь к локальному порту 4001 без указания IP-адреса, а затем отправляете на порт 4001 на удаленном компьютере. Если вы укажете только номер порта в bindтогда IP-адрес будет оставлен как "подстановочный знак", и, следовательно, вы должны получать пакеты, отправленные на этот номер порта на любой из IP-адресов вашей машины.

(Не знаю, почему вы видели бы другое поведение в более ранней версии Qt.)

Проверьте состояние сокета после привязки, прежде чем даже писать или читать.

Смотрите этот код:

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;
    }

Во-вторых, сокеты в Qt будут выдавать сигналы об ошибках, если что-то пойдет не так. Так что у вас должен быть слот для ловли этих сигналов об ошибках. Таким образом, вы можете узнать причину проблемы.

например:

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

Слот для получения ошибок Socker:

void SomeInterface::onSocketError(QAbstractSocket::SocketError socketError)
{
    qDebug()<<"socket error occured and the error is : "<<socketError;
}
Другие вопросы по тегам