【问题标题】:Behaviour of readyRead() signal from QSocket来自 QSocket 的 readyRead() 信号的行为
【发布时间】:2016-12-01 17:50:38
【问题描述】:

我刚刚遇到了来自 QUdpSocket 的 readyRead() 信号的困难时期,虽然我找到了一个解决方案,但我仍然不确定我做了什么,但我想更准确地了解我的解决方案为什么真正有效。这是我的情况:

我已连接到发出通知的服务器。 当我收到它们时,即当我的 QUdpSocket 发出 onReadyRead() 时,我会处理通知:解包数据,检查它的来源等。这是在继承 QObject 的自定义对象中完成的。

然后这个对象发出一个信号“notificationReceived”,以便其他对象可以处理该通知:notificationReceived() 信号连接到一个 processNotification() 槽。

processNotification() 依次执行一些操作,包括向服务器执行新的 GET 请求。 服务器接收请求并做出响应。但是,来自 QUdpSocket 的 readyRead() 信号没有在我的应用程序中发出,它的行为就像它从未从服务器接收到数据报一样。

但是当我调用 'my_socket->hasPendingDatagrams()' 时,它返回 true,我可以读取实际存在的数据报,并且与我在 GET 请求中想要的内容相对应:

MyCustomObject::MyCustomObject(QObject* parent){
    // constructor
    my_socket = new QUdpSocket(this);

    if (!m_socket->bind(QHostAddress::Any, m_port, QAbstractSocket::ShareAddress))
        qDebug() << "Could not bind to port" << m_port << m_socket->errorString();

    connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}

void MyCustomObject::onReadyRead(){
    QHostAddress hostAddress;
    QByteArray data;
    quint16 port;

    while (m_socket->hasPendingDatagrams()) {
        data.resize(my_socket->pendingDatagramSize());
        my_socket->readDatagram(data.data(), data.size(), &hostAddress, &port);
    }

    processResponse(data, hostAddress, port);
}

void MyCustomObject::processNotification(QByteArrayData){
    // do some checking and reading of data
    // when finished:
    getNewData();
}

void MyCustomObject::getNewData(){
    // instantiate data, hostAdress, port. In other words :
    // create the request in the form of a datagram to be sent
    my_socket->writeDatagram(data, hostAdress, port);
}

所以我尝试了解 readyRead() 信号并理解为什么在这种情况下它没有发出。特别是这篇文章给了我一个线索: http://www.qtforum.org/article/1118/2/signal-readyread-doesn-t-work.html

它讲述了线程问题。但是我的应用程序是从 QGuiApplication 运行的,并且一切都在一个线程中完成(据我所知,我实际上对线程了解不多)。

最后,我的解决方案是:直接从 processNotification() 槽接收到 notificationReceived() 信号后,我不执行我的 GET 请求,而是使用 QTimer::singleShot 调用 GET 请求。 所以我做了类似(简化)的事情:

void processNotification(QByteArray data){
    // check some conditions
    // process the data, and when finished:

   QTimer::singleShot(1000, this, SLOT(getData()));
}

并且 getRequest() 负责向服务器发送一个 GET,这一次检测到服务器的响应(my_socket 发出 readyRead() 信号)。虽然我仍然不确定为什么。

注意:如果我不使用,在 notificationReceived() 第一次发出的信号和从最终触发的 slot() 调用 getRequest() 之间发出/接收多少 signal()、slot() 并不重要一个QTimer到底是不行的。

【问题讨论】:

  • 您可能错误地认为 HTTP 服务器实际上已经向您发送了一个 UDP 数据报。使用 Wireshark 确认这样的数据报实际上已经到达您的系统。旁注:当您传递 Qt 容器和其他值类型时,请通过 const 引用传递它们。因此你应该有void processNotification(const QByteArray &amp;data)等。你也可以通过值来保存套接字,没有理由通过指针来保存它。
  • 是的,我确定服务器发送了一个数据报,首先是因为我看到它是在服务器端发送的,其次是因为如果我调用 my_socket->hasPendingDatagrams() 我实际上是在客户端收到它.问题只是即使某些数据正在等待读取,也不会发出 onReadyRead()。
  • 好的,那么确切的操作系统版本和构建是什么,它的 Qt 版本是什么?

标签: c++ qt


【解决方案1】:

我认为你的问题是你在同一个线程和事件循环中做所有事情。

即在您的 readyRead() 插槽中,您正在调用 processResponse(...) 并将立即执行,然后当 processResponse 发出“notificationReceived()”信号并调用 processNotification() 时,最终将调用 getNewData()。

所有这些调用都将“在线”完成(请参阅此链接,了解 Qt 的 DirectConnetion 信号),因此您基本上是在请求 newData 时仍处于 readyRead() 函数调用中。

如果服务器在您的代码流返回到正常事件循环之前响应,那么您将错过新的 readyRead() 调用。

为什么使用 QTimer 可以解决您的问题?因为基本上你推迟了 getNewData 并且你的调用堆栈会离开 readyRead() 并进入正常的事件循环你实际请求一些新数据之前。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多