来自QSocket

时间:2016-12-01 17:50:39

标签: c++ qt

我刚从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()第一个发出的信号和从最终的trigerred slot()调用getRequest()之间发出/接收多少signal(),slot()无关紧要? QTimer最终无效。

1 个答案:

答案 0 :(得分:1)

我认为您的问题是您正在同一线程和事件循环中进行所有操作。

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

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

如果服务器在您的代码流返回正常事件循环之前做出响应,则您将丢失新的readyRead()调用。

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