Как постоянно читать UDP пакеты в QT? - PullRequest
0 голосов
/ 05 сентября 2018

Я отправляю себе UDP-пакеты, как правило, используя этот метод здесь:

Как получить правильный пакет UDP в QT?

Я настраиваю режимы так, чтобы в режиме записи он отправлял UDP-пакеты каждую секунду, а в режиме чтения он просто принимал пакеты. Для этого я установил простую логическую переменную с именем readmode, когда readmode = true, она читает и пишет, когда = false. Я оставил connect(socket, SIGNAL(readyRead()), this,SLOT(readyRead())); и вызов функции send в конструкторе MainWindow и поместил операторы if, проверяя состояние readMode для фактического выполнения чего-либо, в функции send и самих readyRead().

Моя проблема в том, что я получаю пакеты только тогда, когда запускаю программу в режиме чтения, прежде чем открыть окно для записи программы. Если я начну отправлять пакеты до того, как открою программу чтения, я ничего не получу.

Для пояснения я открываю два экземпляра этой программы и устанавливаю один для чтения, а другой для записи, но сначала нужно запустить чтение, чтобы оно заработало, но как только состояния меняются, он перестает работать.

Как я могу заставить его читать все время?

Пример кода:

bool readMode = true; //Write mode = false, Read Mode = true

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    timer = new QTimer(this);
    timer->start(1000);

    ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Read");
    ui->buttonBox->button(QDialogButtonBox::Cancel)->setText("Write");

    out_socket = new QUdpSocket(this);
    out_socket->bind(60500);

    in_socket = new QUdpSocket(this);
    in_socket->bind(60510);

    connect(timer, SIGNAL(timeout()),this,SLOT(UDP_test()));

    connect(in_socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
}    

void MainWindow::UDP_test()                                             //Write Mode
{    
if (readMode == false) //Write Mode                                         
{

    QByteArray Data;
    Data.append(fullResultString);
    out_socket->writeDatagram(Data,QHostAddress("192.168.127.10"),60510);
}           

void MainWindow::readyRead()                                            //Read Mode
{
    if (readMode == true) //Readmode
    {
        while(in_socket->hasPendingDatagrams())
        {
            QByteArray UDPBuffer;

             UDPBuffer.resize(in_socket->pendingDatagramSize());
             QHostAddress sender;
             quint16 senderPort;
             in_socket->readDatagram(UDPBuffer.data(),UDPBuffer.size(), &sender, &senderPort);
}

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

QUdpSocket не генерирует readyRead, если он уже содержит (не считанные) дейтаграммы, когда он получает новую дейтаграмму. Ваш исходный код не завершен. Поэтому мы не видим, как изменить глобальную переменную readMode.

вот простое демонстрационное приложение:

#include <QApplication>
#include <QWidget>
#include <QUdpSocket>
#include <QPushButton>
#include <QListWidget>
#include <QGridLayout>
#include <QDebug>
#include <QUuid>

int main( int argc, char** argv ) {
    QApplication app( argc, argv );

    QWidget form;
    auto*const log_widget = new QListWidget( &form );
    auto*const client = new QUdpSocket( qApp );
    auto*const server = new QUdpSocket( qApp );
    const quint16 TEST_PORT = 31088;

    if( ! server->bind( QHostAddress::LocalHost, TEST_PORT ) ) {
        exit( 1 );
    }

    QObject::connect( server, &QUdpSocket::readyRead, [=]() {
        log_widget->insertItem( 0, "readyRead() has been received" );
    });

    auto*const write_button = new QPushButton( "&Write", &form );
    QObject::connect( write_button, &QPushButton::clicked, [=]() {
        const auto packet = QUuid::createUuid().toByteArray();
        client->writeDatagram( packet, QHostAddress::LocalHost, TEST_PORT );
        log_widget->insertItem( 0, "A datagram has been sent." );
    });

    auto*const read_button = new QPushButton( "&Read", &form );
    QObject::connect( read_button, &QPushButton::clicked, [=]() {
        if( server->hasPendingDatagrams() ) {
            const int size = static_cast< int >( server->pendingDatagramSize() );
            if( size > 0 ) {
                QByteArray packet;
                packet.resize( size );
                server->readDatagram( packet.data(), size );
                log_widget->insertItem( 0, "Read OK: datagram have been read." );
            } else {
                log_widget->insertItem( 0, "Read Error: invalid datagram size." );
            }
        } else {
            log_widget->insertItem( 0, "Read Error: there is no any datagram." );
        }
    });

    auto*const check_button = new QPushButton( "&Check", &form );
    QObject::connect( check_button, &QPushButton::clicked, [=]() {
        if( server->hasPendingDatagrams() ) {
            log_widget->insertItem( 0, "Check: there is at least one datagram." );
        } else {
            log_widget->insertItem( 0, "Check: there is no any datagram." );
        }
    });

    auto*const grid = new QGridLayout( &form );
    grid->addWidget( write_button, 0, 0 );
    grid->addWidget( read_button, 0, 1 );
    grid->addWidget( check_button, 0, 2 );
    grid->addWidget( log_widget, 1, 0, 1, 3 );

    form.show();

    return app.exec();
}
0 голосов
/ 05 сентября 2018

Этого и следовало ожидать: каждый вызов процесса пытается связать входной сокет. В первый раз, когда сокет еще не связан - это удается. Во второй раз - это не удается, поскольку порт уже связан - чтение не будет работать. Все в стороне, код никогда не проверяет на ошибки , и, таким образом, пользователь (то есть вы) не знает, что что-то не так. С проверкой ошибок было бы очевидно, почему это не работает. Выходной сокет не должен быть привязан к явно указанному номеру порта. Входной сокет должен быть связан только тогда, когда программа находится в режиме приема.

...