简体   繁体   中英

Server Sent Events (SSE) with Qt

I already saw several libraries for Server Sent Events, unfortunately, not for Qt. I also looked at the specification of SSE (just plain HTTP) and it seems that implementing SSE in Qt would require to:

  • Use QNetworkAccessManager in streaming mode (download)
  • Accept the content type header of SSE: application/events-stream
  • Reconnect when the connection is lost or closed
  • Attach a slot to the QNAM when new bytes are received (check for data : {...} )

I'm not sure if it's so "easy"? Did I miss something?

I created a small demo with Qt and Server Sent Events. The demo connects to a given EventSource URL (first argument) and prints every event to the command line.

Qt supports SSE out of the box since SSE is pure HTTP with a reconnection layer on top of it.

  1. Prepare the request: set the text/event-stream accept header, allow redirects, disable the cache.
QNetworkRequest Network::Manager::prepareRequest(const QUrl &url)
{
    QNetworkRequest request(url);
    request.setRawHeader(QByteArray("Accept"), QByteArray(ACCEPT_HEADER));
    request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
    request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); // Events shouldn't be cached
    return request;
}
  1. Connect the readyRead signal to a slot.
void Network::Manager::getResource(const QUrl &url)
{
    qDebug() << "GET resource:" << url;
    QNetworkRequest request = this->prepareRequest(url);
    m_reply = this->QNAM()->get(request);
    connect(m_reply, SIGNAL(readyRead()), this, SLOT(streamReceived()));
}
  1. Every time a new event is received by the QNetworkAccessManager, you can read it using readAll . We reset the retries counter after every successful event.
void Network::Manager::streamReceived()
{
    qDebug() << "Received event from stream";
    qDebug() << QString(m_reply->readAll()).simplified().replace("data: ", "");
    qDebug() << "-----------------------------------------------------";
    m_retries = 0;
}
  1. In case we lost the connection or the connection times out, the finished() signal is triggered of the QNetworkAccessManager. We try to reconnect to the event source (We connected this slot to the signal when we created our QNetworkAccessManager instance):
void Network::Manager::streamFinished(QNetworkReply *reply)
{
    qDebug() << "Stream finished:" << reply->url();
    qDebug() << "Reconnecting...";
    if(m_retries < MAX_RETRIES) {
        m_retries++;
        this->getResource(reply->url());
    }
    else {
        qCritical() << "Unable to reconnect, max retries reached";
    }
}

You can find the demo here: https://github.com/DylanVanAssche/Qt-Server-Sent-Events-Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM