QUdpSocket почему не отправляются данные?

243
20 июля 2018, 06:50

Реализую клиент-серверное приложение, в локальной сети может быть несколько клиентов и несколько серверов, клиенты могут "подписаться" на данные от нужных им серверов.

Для удобного получения списка серверов в сети использую широковещательную рассылку по UDP, клиент при старте спрашивает в сеть "есть кто живой?" и собирает ответы от серверов, беря адрес отправителя ответа как адрес сервера.

Если запускать клиент и сервер на одном компьютере, все работает как надо, но если запускать на двух разных компьютерах, то запрос не приходит на сервер. Пробовал два физических ноута и ноут с виртуалкой, в обоих случаях не работает. Фаерволлы и брандмауэры исключил.

В процессе тестирования попробовал добавить задержку в секунду между стартом приложения-клиента и запросом, и все заработало как надо (в виртуалке по крайней мере). И вот тут собственно вопрос - как так?

Понятно, что искусственное выставление задержки это костыль, и для устранения костыля и написания нормального решения нужно понять настоящую причину такого поведения.

Код сервера:

TServer::TServer(QObject *parent) : QObject(parent)
{
    m_udpSocket = new QUdpSocket(this);
    connect(m_udpSocket, &QIODevice::readyRead, this, &TServer::receiveUdpData);
    m_udpSocket->bind(RecGlobalSettings::getUdpClientPort(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint);
}
void TServer::receiveUdpData()
{
    while (m_udpSocket->hasPendingDatagrams())
    {
        QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
        if (!datagram.isValid())
            continue;
        QByteArray data = datagram.data();
        QDataStream dataStream(&data, QIODevice::ReadOnly);
        quint32 datagramType;
        QVariantMap datagramData;
        dataStream >> datagramType;
        dataStream >> datagramData;
        qDebug()<<this<<datagramType<<datagramData;
        if (datagramType == RECNet::WhosThereRequest)
            whosThereReply(datagramData, datagram.senderAddress());
    }
}

Код клиента:

TClient::TClient(QObject *parent) : QObject(parent)
{
    m_udpSocket = new QUdpSocket(this);
    connect(m_udpSocket, &QIODevice::readyRead, this, &TClient::receiveUdpData);
    m_whosThereRequestId = 0;
    m_udpSocket->bind(RecGlobalSettings::getUdpServerPort(), QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint);
}
void TClient::whosThereRequest()
{
    m_whosThereRequestId++;
    QByteArray datagram;
    QDataStream stream(&datagram, QIODevice::WriteOnly);
    QVariantMap variantMap;
    variantMap.insert("requestId", m_whosThereRequestId);
    variantMap.insert("pid", QCoreApplication::applicationPid());
    stream << (quint32)RECNet::WhosThereRequest;
    stream << variantMap;
    m_udpSocket->writeDatagram(datagram, QHostAddress::Broadcast, RecGlobalSettings::getUdpClientPort());
}

Метод TClient::whosThereRequest() вызывается в конструкторе главного окна приложения-клиента сразу же после выделения памяти под класс-клиент.

UPD: Поторопился с "все работает". Если запускать сервер на компе, а клиент в виртуалке, работает нормально. Если наоборот, не работает вообще.

Answer 1

Метод TClient::whosThereRequest() вызывается в конструкторе главного окна приложения-клиента сразу же после выделения памяти под класс-клиент.

Сообщение посредством TClient::whosThereRequest() отправлено, ответ принят, но обработать его некому, т.к. на момент вызова TClient::whosThereRequest() не запущен главный цикл обработки сообщений. Соответственно, сигнал QIODevice::readyRead (в сокете появились новые данные) не приходит. Вполне возможно, что вы получите их со следующей порцией данных, все зависит от конкретной реализации, здесь надо смотреть исходники Qt.

Вызывайте TClient::whosThereRequest() после того, как запустите основной цикл обработки сообщений.

READ ALSO
Почему вылезает ошибка c2280?

Почему вылезает ошибка c2280?

Задача следующая: Реализовать c++ объект, который предоставил бы возможность менять тип данных во время исполненияХранение значения типа...

221
Не работает флаг смены хода

Не работает флаг смены хода

Есть публичное поле класса — gamer, которое служит флагом смены хода

218
Не могу собрать и запустить qt проект

Не могу собрать и запустить qt проект

Скачал я qt и Qt,и решил поизучать,посмотреть

296
variadic templates

variadic templates

Имеется шаблонная функция, принимающая строки

255