【问题标题】:How to properly work with multiple QUdpSockets in Qt in a single Application如何在单个应用程序中正确使用 Qt 中的多个 QUdpSocket
【发布时间】:2020-07-06 14:24:46
【问题描述】:

我创建了一个使用 UDP 协议的服务器和客户端类。在我的应用程序中,我用不同的端口实例化了 4 个服务器对象和 4 个客户端对象。

问题是我同时从 4 个客户端向 4 个服务器发送数据,但是每个服务器只有在前一个服务器完成工作时才接收它的数据...

为什么会这样?

这是我的代码:

主要:

std::thread thread;

client cl1(4235),cl2(4245),cl3(4255),cl4(4265);

void handler()
{
    while(1){

        cl1.SendData("HI1",4230);
        cl2.SendData("HI2",4240);
        cl3.SendData("HI3",4250);
        cl4.SendData("HI4",4260);
        std::this_thread::sleep_for(std::chrono::seconds(50));
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    server s1(4230);
    server s2(4240);
    server s3(4250);
    server s4(4260);
    thread = std::thread(handler);
    return a.exec();
}

服务器类:

class server : public QObject
{
    Q_OBJECT
public :
    server(int port)
    {
        this->port = port;
        udpSocket = new QUdpSocket();
            udpSocket->bind(QHostAddress::LocalHost, port);

            connect(udpSocket, SIGNAL(readyRead()),
                    this, SLOT(readPendingDatagrams()));
    };
   public  slots:
    void readPendingDatagrams()
    {
        while (udpSocket->hasPendingDatagrams()) {
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;

            udpSocket->readDatagram(datagram.data(), datagram.size(),
                                    &sender, &senderPort);

            //processTheDatagram(datagram);
            QDateTime dateTime;
            dateTime = dateTime.currentDateTime();
            qDebug() << QString::number(dateTime.time().hour()).rightJustified(2, '0') + ":" +//hour
                        QString::number(dateTime.time().minute()).rightJustified(2, '0') + ":" +//minute
                        QString::number(dateTime.time().second()).rightJustified(2, '0');//seconds
            qDebug() << "\t\tdata received from:" << sender.toString() <<":"<<senderPort << "  data:" << datagram;


            std::this_thread::sleep_for(std::chrono::seconds(5));

            qDebug() << QString::number(dateTime.time().hour()).rightJustified(2, '0') + ":" +//hour
                        QString::number(dateTime.time().minute()).rightJustified(2, '0') + ":" +//minute
                        QString::number(dateTime.time().second()).rightJustified(2, '0');//seconds
            qDebug () << "Sending Response";
            udpSocket->writeDatagram(("HI back from" + QString::number(port)).toUtf8(),sender,senderPort);
        }
    };

private:
    QUdpSocket * udpSocket;
    int port;
};

客户端类:

class client : public QObject
{
    Q_OBJECT
   public:
    client(int port) {
        this->port = port;
        udpSocket = new QUdpSocket();
            udpSocket->bind(QHostAddress::LocalHost, port);

            connect(udpSocket, SIGNAL(readyRead()),
                    this, SLOT(readPendingDatagrams()));
    }
    void SendData(QString Data,int serverport)
    {
        QDateTime dateTime;
        dateTime = dateTime.currentDateTime();


        udpSocket->writeDatagram(Data.toUtf8(),QHostAddress::LocalHost,serverport);
        qDebug() << QString::number(dateTime.time().hour()).rightJustified(2, '0') + ":" +//hour
                    QString::number(dateTime.time().minute()).rightJustified(2, '0') + ":" +//minute
                    QString::number(dateTime.time().second()).rightJustified(2, '0')//sec
                 << "\tclient : " <<port << " sending data to server:" << Data;
    }
   public  slots:
    void readPendingDatagrams()
    {
        while (udpSocket->hasPendingDatagrams()) {
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;

            udpSocket->readDatagram(datagram.data(), datagram.size(),
                                    &sender, &senderPort);

            //processTheDatagram(datagram);
            QDateTime dateTime;
            dateTime = dateTime.currentDateTime();
            qDebug() << QString::number(dateTime.time().hour()).rightJustified(2, '0') + ":" +//hour
                        QString::number(dateTime.time().minute()).rightJustified(2, '0') + ":" +//minute
                        QString::number(dateTime.time().second()).rightJustified(2, '0');//seconds
            qDebug() << "\t\tclient : " <<port << " data received from:" << sender.toString() <<":"<<senderPort << "  data:" << datagram;
        }
    }

private:
    QUdpSocket * udpSocket;
    int port;
};

这是我的输出数据:

"18:50:07"  client :  4235  sending data to server: "HI1"
"18:50:07"  client :  4245  sending data to server: "HI2"
"18:50:07"  client :  4255  sending data to server: "HI3"
"18:50:07"  client :  4265  sending data to server: "HI4"
"18:50:07"
        data received from: "127.0.0.1" : 4235   data: "HI1"
"18:50:07"
Sending Response
"18:50:12"
        data received from: "127.0.0.1" : 4245   data: "HI2"
"18:50:12"
Sending Response
"18:50:17"
        data received from: "127.0.0.1" : 4255   data: "HI3"
"18:50:17"
Sending Response
"18:50:22"
        data received from: "127.0.0.1" : 4265   data: "HI4"
"18:50:22"
Sending Response

【问题讨论】:

  • 那么,您是在同一个程序中创建客户端和服务器吗?这可能会造成阻塞条件。您可以尝试从两个程序中执行此操作吗?另外,我使用 receiveDatagram 而不是 readDatagram,我没有体验到您报告的内容。
  • 我已经在单个服务器中尝试过这个服务器类并在多个进程中执行它,它完全没问题,我在上面描述的情况下遇到了问题......我会尝试你推荐的功能和让你知道结果。谢谢。
  • 你为什么在这里使用线程?所有clientserver 实例都在“主”线程上创建,但随后可能从该线程和辅助线程访问。这是未定义的行为。

标签: c++ qt udp qudpsocket


【解决方案1】:
std::this_thread::sleep_for(std::chrono::seconds(5)); 

正在阻塞您当前的线程。看看你的 main(),这也阻塞了主应用程序线程。因此,您的应用程序将不会从操作系统接收有关传入数据包的消息。 如果要并行处理数据,则不应在连接到 readyRead 信号的插槽内使用睡眠函数。

【讨论】:

  • 请再看一下我的代码,问题不是线程休眠,这是4个不同的对象和线程,我只是把那个线程休眠来显示我的问题。
  • 回复。 "these are 4 diferent obejcts and threads":不,有 4 个服务器和 4 个客户端,但只有 2 个线程——main 正在执行的线程和全局定义的thread
  • 为了放大 GM(正确)所说的,你有一个用于客户端的线程,另一个用于服务器。我在第一次通读时错过了睡眠功能,但这解释了你看到的间隔。您需要为 每个 服务器/客户端显式创建线程,然后再次为每个实例使用 moveToThread() 和 thread->start()。
  • @G.M.你是对的,我认为“QUdpSocket”的每个实例都有自己的线程,我按照你和 mzimmers 所说的将数据推送到另一个线程来处理它们。谢谢你们,很抱歉迟到的反馈。
猜你喜欢
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 2015-04-23
  • 2018-05-11
相关资源
最近更新 更多