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

0

Я пытаюсь получить некоторые пакеты, используя класс 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. Я ценю, если вы могли бы помочь мне решить эту проблему :) С уважением,

Теги:
multithreading
qt
sockets
qthread

2 ответа

1
Лучший ответ

Вы попали в ту же ловушку, что и многие, когда работаете с потоками в Qt: http://blog.qt.digia.com/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"

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

  • 0
    Отличный ответ, спасибо! однако, когда я использую то, что вы предложили, я получаю это сообщение в консоли несколько раз: «QSocketNotifier: уведомления о сокетах нельзя отключить из другого потока» Это то, о чем мне следует беспокоиться (отключение сокетов из другого потока)? Как я могу это исправить?
  • 0
    Извините, я никогда не видел это сообщение. Может быть, вы должны опубликовать новый вопрос. Если бы у меня было время, я мог бы взглянуть.
0

Вахид Натеги, коды инициализации и рабочие коды должны работать в одном потоке. Но конструктор 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"

Ещё вопросы

Сообщество Overcoder
Наверх
Меню