пакет udp не получен в QThread

Я пытаюсь получить некоторые пакеты, используя класс udpReceiver, который я написал, используя qUdpSocket в отдельном QThread:

class udpThread : public QThread
{
private:
    QObject * parent;
public:
    udpThread(QObject * parent = 0)
    {
        this->parent = parent;
    }

    void run()
    {
        UdpReceiver * test = new UdpReceiver(parent);
    }
};


class UdpReceiver : public QObject
{
    Q_OBJECT
private:
    QUdpSocket * S;
    int port;
public:
    UdpReceiver(QObject* parent = 0) : QObject(parent)
    {
        port = 9003;
        initialize();
    }
    UdpReceiver(int p,QObject* parent = 0) : QObject(parent)
    {
        port = p;
        initialize();
    }

    void initialize()
    {
        S = new QUdpSocket();
        S->bind(port);
        S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
        qDebug() << "Waiting for UDP data from port " << port << " ... \n";
    }

public slots:
    void readPendingDiagrams()
    {
        while(S->waitForReadyRead())
        {
            QByteArray datagram;
            datagram.resize(S->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;

            S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
            qDebug() << datagram.size() << " bytes received .... \n";
            qDebug() << " bytes received .... \n";
        }
    }
};

А вот метод main():

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);



//    UdpReceiver * net = new UdpReceiver();      

    MainWindow w;

    udpThread * ut = new udpThread();
    ut->start();

    w.show();


    return a.exec();
}

Теперь, когда я использую класс udpReceiver для получения пакетов без QThread, он работает просто отлично, но когда я использую класс udpThread, он не получает пакеты или, по крайней мере, сигнал raedyread() каким-то образом не активируется. Когда я пытаюсь получить пакеты без QThread, мой графический интерфейс почему-то падает, и вся программа зависает, поэтому я хочу использовать QThread. Я ценю, если вы могли бы помочь мне решить эту проблему :) С уважением,


person Vahid Nateghi    schedule 15.10.2013    source источник
comment
Вы пропустили какой-то код в своей функции run(). Все, что вам нужно сделать, это создать свой UdpReceiver, а затем выйти из текущего потока.   -  person RobbieE    schedule 15.10.2013


Ответы (2)


Вы попали в ту же ловушку, что и многие, работая с потоками в Qt: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/.
почти всегда плохая идея создавать подкласс QThread (см. http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html для контрпримеров).

Измените свой код следующим образом, чтобы сделать его "предполагаемым" способом (создайте новый QThread и вызовите moveToThread на своем QObject, чтобы переместить его в новый поток). Из вывода вы увидите, что поток, в котором создается UdpReceiver, не совпадает с тем, в котором он получает данные, а это то, что вам нужно:

#include <QApplication>
#include <QDebug>
#include <QThread>
#include <QUdpSocket>

class UdpReceiver : public QObject
{
    Q_OBJECT
private:
    QUdpSocket * S;
    int port;
public:
    UdpReceiver(QObject* parent = 0) : QObject(parent)
    {
        qDebug() << "Construction thread:" << QThread::currentThreadId();

        port = 9003;
        initialize();
    }
    UdpReceiver(int p,QObject* parent = 0) : QObject(parent)
    {
        port = p;
        initialize();
    }

    void initialize()
    {
        S = new QUdpSocket();
        S->bind(port);
        S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
        qDebug() << "Waiting for UDP data from port " << port << " ... \n";
    }

public slots:
    void readPendingDiagrams()
    {
        qDebug() << "Reading thread:" << QThread::currentThreadId();

        while(S->waitForReadyRead())
        {
            QByteArray datagram;
            datagram.resize(S->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;

            S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
            qDebug() << datagram.size() << " bytes received .... \n";
            qDebug() << " bytes received .... \n";
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QThread *t = new QThread();
    t->start();

    UdpReceiver * net = new UdpReceiver();
    net->moveToThread(t);

    return a.exec();
}

#include "main.moc"

У меня нет вашего кода UI, поэтому я не знаю о каких-либо проблемах. Не стесняйтесь задавать еще один вопрос, если вы застряли там, и упомянуть его в комментарии, и я постараюсь помочь.

person ksimons    schedule 15.10.2013
comment
Отличный ответ, спасибо! однако, когда я использую то, что вы предложили, я несколько раз получаю это сообщение в консоли: QSocketNotifier: уведомители сокетов не могут быть отключены из другого потока. Я должен беспокоиться об этом (отключение сокетов из другого потока)? Как я могу это исправить? - person Vahid Nateghi; 21.10.2013
comment
Извините, я никогда не видел это сообщение. Возможно, вам следует опубликовать новый вопрос. Если у меня будет немного времени позже, я мог бы взглянуть. - person ksimons; 21.10.2013

Вахид Натеги, коды инициализации и рабочие коды должны выполняться в одном потоке. Но конструктор UdpReceiver запускается в основном потоке против одного, в котором запускается readPendingDiagrams, в этом и была ошибка. Попробуй это:

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QUdpSocket>

class UdpReceiver : public QObject
{
    Q_OBJECT
private:
    QUdpSocket * S;
    int port;
public:
    UdpReceiver(QObject* parent = 0) : QObject(parent)
    {
        qDebug() << ">HERE was the bug! thread:" << QThread::currentThreadId() << "in Construction of UdpReceiver:" << __LINE__ ;
    }

public slots:
    void init_thread(){
        port = 10000;
        qDebug() << ">thread:" << QThread::currentThreadId() << "in init_thread:" << __LINE__ ;
        S = new QUdpSocket();
        S->bind(port);
        S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
        qDebug() << "Waiting for UDP data from port " << port << " ... \n";
    }
    void readPendingDiagrams()
    {
        qDebug() << ">thread:" << QThread::currentThreadId() << "in readPendingDiagrams:" << __LINE__ ;


        while(S->waitForReadyRead())
        {
            QByteArray datagram;
            datagram.resize(S->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;

            S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
            qDebug() << datagram.size() << " bytes received in thread " << QThread::currentThreadId() << "in readPendingDiagrams:" << __LINE__ ;
        }
    }
};

int main(int argc, char *argv[])
{
    qDebug() << ">Main thread:" << QThread::currentThreadId() << "in main:" << __LINE__ ;
    QCoreApplication a(argc, argv);

    QThread *t = new QThread();


    UdpReceiver * net = new UdpReceiver();
    net->moveToThread(t);
    net->connect(t,SIGNAL(started()),net,SLOT(init_thread()));
    t->start();

    return a.exec();
}

#include "main.moc"
person Victor Lue    schedule 21.07.2016