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()
События.