我可以在Qt中使用QUdpSockets轮询或自定义类吗?

Can I use QUdpSockets wo polling or custom classes in Qt?

本文关键字:自定义 QUdpSockets Qt 我可以      更新时间:2023-10-16

下面是Qt中的一个简短的UDP服务器示例,它确实有效,但我不喜欢的是我正在轮询以查看是否有新数据可用。我遇到过一些 readyRead() 的例子,但它们似乎都引入了一个 qt 类。我是否需要使用 qt 类才能利用 readyRead() 信号?

这是完全在main中实现的工作但简单的UDP服务器:

#include <QDebug>
#include <QUdpSocket>
#include <QThread>
int main(int argc, char *argv[])
{
    QUdpSocket *socket = new QUdpSocket();
    u_int16_t port = 7777;
    bool bindSuccess =  socket->bind(QHostAddress::AnyIPv4, port);
    if (!bindSuccess) {
        qDebug() << "Error binding to port " << port << " on local IPs";
        return a.exec();
    }
    qDebug() << "Started UDP Server on " << port << endl;
    QHostAddress sender;
    while (true) {
        while (socket->hasPendingDatagrams()) {
            QByteArray datagram;
            datagram.resize(socket->pendingDatagramSize());
            socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
            qDebug() << "Message From :: " << sender.toString();
            qDebug() << "Port From :: "<< port;
            qDebug() << "Message :: " << datagram.data();
        }
        QThread::msleep(20);
    }
    return 0;
}

下面是 readyRead() 信号的示例:https://www.bogotobogo.com/Qt/Qt5_QUdpSocket.php

我还没有真正弄清楚如何让它工作。我一定是做错了什么。这是我正在尝试的UDP连接代码:

#include "myudp.h"
MyUDP::MyUDP(QObject *parent) : QObject(parent) {
}
void MyUDP::initSocket(u_int16_t p) {
    port = p;
    udpSocket = new QUdpSocket(this);
    bool bindSuccess = udpSocket->bind(QHostAddress::LocalHost, port);
    if (!bindSuccess) {
        qDebug() << "Error binding to port " << port << " on local IPs";
        return;
    }
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
void MyUDP::readPendingDatagrams() {
    QHostAddress sender;
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
        qDebug() << "Message From :: " << sender.toString();
        qDebug() << "Port From :: " << port;
        qDebug() << "Message :: " << datagram.data();
    }
}

缪德普·

#include <QObject>
#include <QUdpSocket>
class MyUDP : public QObject
{
    Q_OBJECT
public:
    explicit MyUDP(QObject *parent);
    void initSocket(u_int16_t p);
    u_int16_t port;
    QUdpSocket *udpSocket;
signals:
public slots:
    void readPendingDatagrams();
};

新主.cpp

int main(int argc, char *argv[]) 
{
    MyUDP *myUDP = new MyUDP(0);
    myUDP->initSocket(port);
    while (true) {
        usleep(1000);
    }
    return 0;
}

我正在测试:

netcat 127.0.0.1 -u 7777
{"cid"="0x1234123412341", "fill_level"=3245 }<cr>

你做错的是你没有让Qt的事件循环运行。 即这是不正确的:

int main(int argc, char *argv[]) 
{
   MyUDP *myUDP = new MyUDP(0);
   myUDP->initSocket(port);
   while (true) {
       usleep(1000);
   }
   return 0;
}

。相反,你应该有这样的东西:

int main(int argc, char *argv[]) 
{
   QApplication app(argc, argv);
   // connect needs to occur after QCoreApplication declaration
   MyUDP *myUDP = new MyUDP(0);
   myUDP->initSocket(port);
   return app.exec();
}

。Qt应用程序大部分时间都在app.exec()调用中花费(app.exec()在Qt想要退出之前不会返回),Qt将处理UDP套接字的I/O和信令需求。

请像这样修改您的进程挂起数据报,以允许处理较新的传入数据:

void MyUDP::readPendingDatagrams() {
    QHostAddress sender;
    uint16_t port;
    QByteArray datagram; // moved here
    while (udpSocket->hasPendingDatagrams()) {
        //QByteArray datagram; // you don't need this here
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
        qDebug() << "Message From :: " << sender.toString();
        qDebug() << "Port From :: " << port;
        qDebug() << "Message :: " << datagram.data();
    }
    // God knows why, there is always one more "dummy" readDatagram call to make, 
    // otherwise no new readyRead() will be emitted, and this function would never be called again
    datagram.resize(udpSocket->pendingDatagramSize());
    socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
}