Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在QT中不断读取UDP数据包?_C++_Qt_Sockets_Udp - Fatal编程技术网

C++ 如何在QT中不断读取UDP数据包?

C++ 如何在QT中不断读取UDP数据包?,c++,qt,sockets,udp,C++,Qt,Sockets,Udp,我在这里使用此方法向自己发送UDP数据包: 我正在设置模式,以便在写模式下,它每秒发送UDP数据包,在读模式下,它只接收数据包。为此,我设置了一个名为readmodewhen readmode=true的简单布尔变量,它在=false时读取和写入。我留下了连接(套接字,信号(readyRead()),这个,插槽(readyRead())和调用main窗口中的send函数构造函数,并将if语句放入send函数和readyRead()函数本身中,测试readMode的状态以实际执行某些操作 我的问

我在这里使用此方法向自己发送UDP数据包:

我正在设置模式,以便在写模式下,它每秒发送UDP数据包,在读模式下,它只接收数据包。为此,我设置了一个名为
readmode
when readmode=
true
的简单布尔变量,它在=
false
时读取和写入。我留下了
连接(套接字,信号(readyRead()),这个,插槽(readyRead())
和调用
main窗口中的send函数
构造函数,并将
if
语句放入send函数和
readyRead()
函数本身中,测试
readMode
的状态以实际执行某些操作

我的问题是,在打开程序写入窗口之前,我只在以读取模式启动程序时接收数据包。如果我在打开读取程序之前就开始发送数据包,我将一无所获

为了澄清,我打开了这个程序的两个实例,我将其中一个设置为Read,另一个设置为Write,但是必须先启动Read,它才能工作,但是一旦状态发生变化,它就会停止工作

我怎样才能让它一直读下去

代码示例:

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);
}

这是意料之中的:流程的每次调用都试图绑定输入套接字。第一次,在套接字尚未绑定的情况下,它成功了。第二次-它失败了,因为端口已经绑定-所以读取将不起作用。抛开一切不谈,代码从不检查错误,因此用户(即您)不知道出现了故障。通过错误检查,很明显它为什么不工作。输出套接字不需要绑定到显式指定的端口号。仅当程序处于接收模式时,才应绑定输入套接字。

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();
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
QApplication应用程序(argc、argv);
QWidget表单;
auto*const log_widget=新的QListWidget(&form);
auto*const client=新的QUdpSocket(qApp);
auto*const server=新的QUdpSocket(qApp);
const quint16测试端口=31088;
如果(!服务器->绑定(QHostAddress::LocalHost,测试端口)){
出口(1);
}
QObject::connect(服务器,&QUdpSocket::readyRead,[=](){
log_widget->insertItem(0,“readyRead()已收到”);
});
auto*const write_button=新的QPushButton(“&write”,&form”);
QObject::connect(写入按钮,&QPushButton::单击,[=](){
const auto packet=quid::createUuid().toByteArray();
client->writeDatagram(数据包,QHostAddress::LocalHost,测试端口);
log_widget->insertItem(0,“已发送数据报”);
});
auto*const read_button=新的QPushButton(“&read”,&form”);
QObject::connect(读取按钮,&QPushButton::单击,[=](){
如果(服务器->hasPendingDatagrams()){
const int size=static_cast(服务器->pendingDatagramSize());
如果(大小>0){
QByteArray包;
数据包。调整大小(大小);
服务器->读取数据报(packet.data(),大小);
log_widget->insertItem(0,“读取确定:数据报已读取”);
}否则{
log_widget->insertItem(0,“读取错误:数据报大小无效”);
}
}否则{
log_widget->insertItem(0,“读取错误:没有任何数据报”);
}
});
自动*const check_按钮=新的QPushButton(“&check”、&form”);
QObject::connect(选中按钮,&QPushButton::单击,[=](){
如果(服务器->hasPendingDatagrams()){
log_widget->insertItem(0,“检查:至少有一个数据报”);
}否则{
log_widget->insertItem(0,“检查:没有任何数据报”);
}
});
auto*const grid=新的QGridLayout(&form);
grid->addWidget(写入按钮,0,0);
grid->addWidget(读取按钮,0,1);
网格->添加小部件(选中按钮,0,2);
网格->添加小部件(日志小部件,1,0,1,3);
form.show();
返回app.exec();
}

在这种情况下,错误检查是什么样子的?idk,这是我的代码的精简版本,问题出在这里,但我可能已经有了“错误检查”,您介意澄清一下吗?当您在套接字上调用方法时,不要忽略它的返回值,除非您可以解释为什么这样做。在示例代码中,您必须检查
bind
writeDatagram
等的返回值。我又做了一天这方面的工作,我不确定它要在哪里再次绑定端口。它绑定它一次,然后移动到ready read。第二个失败的绑定在哪里?给定IP地址+IP协议对的端口是系统全局资源。您必须考虑绑定到端口的所有进程,而不仅仅是您想到的一个进程。请记住,您正在启动两个过程。他们每个人都试图束缚自己。只有第一个过程才会成功。在第一个进程终止或解除绑定套接字之前,不会有其他进程终止或解除绑定,以先到者为准。在流程中只绑定一次并不重要,而是跨流程绑定多次。谢谢,我解决了这个问题。如果您有时间,我将如何使端口随我提出的每个实例而更改?
bool
ean变量应设置为/tested-by
true
/
false
,而不是
1
/
0
。尽管这可能只是一个坏主意,令人困惑(你让读者认为这是一个
int
),但我用按钮来改变状态。按下读取时,
readMode
变为true,按下写入时