Qt QUdpSocket: сигнал readyRead() и соответствующий слот не работают должным образом

У меня есть проблемы, чтобы найти, почему мой короткий QUdpSocket пример не работает. Я планирую использовать только один сокет UDP для чтения и записи во встроенное устройство по адресу 192.168.2.66 на порту 2007. Устройство будет всегда отвечать отправителю на порту 2007. Я протестировал устройство с программным обеспечением терминала UDP и работает как я сказал. Итак, я разработал простой класс для встраивания функций, необходимых для управления устройством:

class QUdp : public QObject
{
    // Q_OBJECT
public:
    explicit QUdp(QObject *parent = 0, const char *szHost = 0, uint16_t wPort = 0);
    ~QUdp();
    bool Open();
    int64_t Write(QByteArray &data);
    int64_t Write(QString strData);
private:
    QString m_strHost;
    uint16_t m_wPort;
    QUdpSocket *OUdp;
private slots:
    void received();
};

Я полагаю, что проблема в методе Open:

bool QUdp::Open()
{
    QHostAddress OHost;
    connect(OUdp, &QUdpSocket::readyRead, this, &QUdp::received);
    bool zRet = OUdp->bind(QHostAddress::AnyIPv4, m_wPort, QUdpSocket::ShareAddress);
    OHost.setAddress(m_strHost);
    OUdp->connectToHost(OHost, m_wPort, QIODevice::ReadWrite);
    return(zRet);
}
//------------------------------------------------------------------------

Я использовал синтаксис Qt 5 для connect(), m_strHost значение равно "192.168.2.66" и m_wPort это 2007

Мой метод записи очень прост (часть внутри #if 0 была добавлена, чтобы увидеть, получил ли сокет какие-либо данные)

int64_t QUdp::Write(QString strData)
{
    QByteArray data(strData.toStdString().c_str(), strData.length());
    int64_t iCount = OUdp->write(data);
#if 0
    bool zRecved = OUdp->waitForReadyRead(3000);
    int64_t iRecvCount = OUdp->bytesAvailable();
#endif
    return(iCount);
}
//------------------------------------------------------------------------

и это мой метод метода test ()... Я написал его только для того, чтобы проверить, работает ли сигнальный слот или нет:

void QUdp::received()
{
    int64_t iRecvCount = OUdp->bytesAvailable();
}
//------------------------------------------------------------------------

Я не понимаю, что не так.. Я нашел несколько сообщений, в которых говорится, что невозможно читать и писать, используя только один UDP-сокет в Qt (Qt использует BSD-сокеты, поэтому это должно быть возможно), но мой пример выглядит как предлагаемые решения, поэтому я действительно не понимаю, что не работает.

1 ответ

Вы можете читать и писать, используя только один сокет UDP в Qt. У меня это работает в Qt5 как на Windows, так и на Linux, так что не беспокойтесь там:)

Чтобы установить прямую связь Rx в QUdpSocket Вы должны действительно использовать функцию bind(), что-то вроде этого:

// Rx connection: check we are not already bound
if (udpSocket->state() != udpSocket->BoundState)
{
    // Rx not in bound state, attempt to bind
    udpSocket->bind(address, port);
}

После этого вы сможете проверить, что udpSocket->state() == udpSocket->BoundState Это правда, тогда вы успешно "привязаны" к этому IP / порту. Теперь ваше прослушивание может начаться, если ваше соединение с readready() верно. Я не использовал этот синтаксис соединения, который вы используете, поэтому я не могу много говорить об этом, но вот пример того, как я подключаюсь:

connect(udpSocket, SIGNAL(readyRead()), this, SLOT(rxDataEvent()), Qt::QueuedConnection);

Где "это" класс, который содержит мой QUdpSocket а также udpSocket это QUdpSocket указатель. затем rxDataEvent определяется ниже:

void CIpComms::rxDataEvent(void)
{
    QByteArray rxData;
    QHostAddress sender;
    quint16 senderPort;

    while (udpSocket->hasPendingDatagrams())
    {
        // Resize and zero byte buffer so we can make way for the new data.
        rxData.fill(0, udpSocket->pendingDatagramSize());

        // Read data from the UDP buffer.
        udpSocket->readDatagram(rxData.data(),
                                rxData.size(),
                                &sender,
                                &senderPort);

        // Emit ipDataReceived Signal
        emit ipDataReceived(rxData);
    }
}

Здесь мы постоянно проверяем дейтаграммы до тех пор, пока они не ожидают (немного проще, чем делать всю "bytesAvailable вещь") и вставляем данные в QByteArray и испустить его в другом месте (что вам, очевидно, не нужно делать!).

Это все, что вам нужно сделать для подключения. Тогда отправить очень просто, нужно просто позвонить writeDatagram()Ну, есть и другие варианты, но это гораздо проще в использовании:

if (-1 == udpSocket->writeDatagram(txData, address, port))
{
    // Data write failed, print out warning
    qWarning() << "Unable to write data to " << address.toString() << ":" << port << endl;
    return false;
}

Я в значительной степени вырезал и вставил это из моего рабочего кода (с несколькими изменениями, чтобы сделать его кратким и простым, поэтому он должен дать вам отправную точку. В итоге, я полагаю, что вы идете не так, как будто вы не "ограничены" "на IP-адрес / порт и, следовательно, НЕ слушают его и не будут получать какие-либо readReady() События.

Другие вопросы по тегам