Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTcpSockets added to QList seem to disappear from list
Forum Updated to NodeBB v4.3 + New Features

QTcpSockets added to QList seem to disappear from list

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 5 Posters 923 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    black_spot1984
    wrote on last edited by
    #1

    I am creating a QTcpServer to send a MJPEG stream to clients that connect to the server. When I get a newConnection signal from the server I add the QTcpSocket to a QList. Then a different function gets frames and looks to see if the QList is non-empty. The problem is that even after I get a connection the QList from the other function's perspective remains empty.

    I setup the QTcpServer like this:

    server = new QTcpServer(this);
    
    connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
    

    Then on each new connection:

    void 
    MjpegServer::newConnection() {
    
        if(!socketMutex.tryLock(1000)) {
            qCritical() << "Could not lock sendFrame Mutex to add new client";
            return;
        }
    
        while(server->hasPendingConnections()) {
            qInfo() << "Got new MJPEG Connection";
            m_clients.append(server->nextPendingConnection());
    
            QByteArray ContentType = ("HTTP/1.0 200 OK\r\n" \
                "Cache-Control: no-cache\r\n" \
                "Pragma: no-cache\r\n" \
                "Connection: close\r\n" \
                "Content-Type: multipart/x-mixed-replace; boundary=mjpegstream\r\n\r\n");
            m_clients.last()->write(ContentType);
            m_clients.last()->flush();
            m_clients.last()->waitForBytesWritten(3000);
    
            connect(m_clients.last(), &QTcpSocket::disconnected, this, &MjpegServer::socketDisconnected);
            connect(m_clients.last(), SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
    
            qInfo() << "Clients now connected: " + QString::number(m_clients.count());
        }
    
        socketMutex.unlock();
    }
    

    When I run the code and a client connects, I get a printout saying that m_clients.count() is 1. I have a function that sends video frames:

    void
    MjpegServer::sendFrame(Mat &img) {
    
        if(!socketMutex.tryLock(1000)) {
            qCritical() << "Could not lock sendFrame Mutex";
            return;
        }
    
        // Only encode if there are connected clients
        if(m_clients.count() == 0) {
            socketMutex.unlock();
            qInfo() << "No clients";
            return;
        }
    
        qInfo() << "Encoding image";
        std::vector<uchar> outbuf;
        std::vector<int> params;
        params.push_back(CV_IMWRITE_JPEG_QUALITY);
        params.push_back(100);
        imencode(".jpg", img, outbuf, params);
    
        std::string content(outbuf.begin(), outbuf.end());
        QByteArray CurrentImg(QByteArray::fromStdString(content));
        QByteArray BoundaryString = ("--mjpegstream\r\nContent-Type: image/jpeg\r\nContent-Length: ");
        BoundaryString.append(QString::number(CurrentImg.length()));
        BoundaryString.append("\r\n\r\n");
    
        for( int i=0; i < m_clients.count(); ++i ) {
            qInfo() << "Writing data to client " + QString::number(i);
            QTcpSocket* socket = m_clients.at(i);
            socket->write(BoundaryString);
            socket->write(CurrentImg); // Write The Encoded Image
            socket->flush();
        }
        socketMutex.unlock();
    }
    

    Right now this only ever prints "No clients". Even after a client has connected. I also have signals connected to monitor when QTcpSockets are disconnected or their state changes, these signals do not fire. The QTcpSockets connect, seem not to disconnect, but the sendFrame function cannot see them in the QList.

    Any help would be appreciated...

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Any chances that you have cleanup functions that is called at some point earlier than you thought ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • B Offline
        B Offline
        black_spot1984
        wrote on last edited by
        #3

        It definitely feels like something along those lines. I do not see a place where this might be occurring. I'm hoping another set of eyes might be able to see what I do not:

        #include "MjpegServer.h"
        
        MjpegServer::MjpegServer(QObject *parent, int port) :
          QObject(parent), port(port) 
        {
          server = new QTcpServer(this);
        
          connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
        
          if (!server->listen(QHostAddress::Any, port))
              qCritical() << "Server NOT started";
          else
              qInfo() << "MJPEG Server started on port " + QString::number(port);
        }
        
        MjpegServer::~MjpegServer() {
        }
        
        void 
        MjpegServer::newConnection() {
        
            if(!socketMutex.tryLock(1000)) {
                qCritical() << "Could not lock sendFrame Mutex to add new client";
                return;
            }
        
            while(server->hasPendingConnections()) {
                qInfo() << "Got new MJPEG Connection";
                m_clients.append(server->nextPendingConnection());
        
                connect(m_clients.last(), SIGNAL(readyRead()), this, SLOT(writeHeader()));
                connect(m_clients.last(), &QTcpSocket::disconnected, this, &MjpegServer::socketDisconnected);
                connect(m_clients.last(), SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
        
                qInfo() << "Clients now connected: " + QString::number(m_clients.count());
            }
        
            socketMutex.unlock();
        }
        
        void
        MjpegServer::socketDisconnected() {
          QTcpSocket *pClient = qobject_cast<QTcpSocket *>(sender());
          qInfo() << "MJPEG socket Disconnected:" << pClient;
          if (pClient) {
            m_clients.removeAll(pClient);
            pClient->deleteLater();
          }
        }
        
        void
        MjpegServer::onSocketStateChanged(QAbstractSocket::SocketState socketState)
        {
            qInfo() << "MJPEG socket state changed to " + QString::number(socketState);
            if (socketState == QAbstractSocket::UnconnectedState)
            {
                QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
                m_clients.removeOne(sender);
            }
        }
        
        void
        MjpegServer::writeHeader() {
          QTcpSocket *pClient = qobject_cast<QTcpSocket *>(sender());
        
          qInfo() << "Writing MJPEG header info";
          QByteArray ContentType = ("HTTP/1.0 200 OK\r\n" \
              "Cache-Control: no-cache\r\n" \
              "Pragma: no-cache\r\n" \
              "Connection: close\r\n" \
              "Content-Type: multipart/x-mixed-replace; boundary=mjpegstream\r\n\r\n");
          pClient->write(ContentType);
          pClient->flush();
        }
        
        void
        MjpegServer::sendFrame(Mat &img) {
        
            if(!socketMutex.tryLock(1000)) {
                qCritical() << "Could not lock sendFrame Mutex";
                return;
            }
        
            // Only encode if there are connected clients
            if(m_clients.count() == 0) {
                socketMutex.unlock();
                qInfo() << "No clients";
                return;
            }
        
            qInfo() << "Encoding image";
            std::vector<uchar> outbuf;
            std::vector<int> params;
            params.push_back(CV_IMWRITE_JPEG_QUALITY);
            params.push_back(100);
            imencode(".jpg", img, outbuf, params);
        
            std::string content(outbuf.begin(), outbuf.end());
            QByteArray CurrentImg(QByteArray::fromStdString(content));
            QByteArray BoundaryString = ("--mjpegstream\r\nContent-Type: image/jpeg\r\nContent-Length: ");
            BoundaryString.append(QString::number(CurrentImg.length()));
            BoundaryString.append("\r\n\r\n");
        
            for( int i=0; i < m_clients.count(); ++i ) {
                qInfo() << "Writing data to client " + QString::number(i);
                QTcpSocket* socket = m_clients.at(i);
                socket->write(BoundaryString);
                socket->write(CurrentImg); // Write The Encoded Image
                socket->flush();
            }
            socketMutex.unlock();
        }
        

        The header file:

        #ifndef MJPEGSERVER_H
        #define MJPEGSERVER_H
        
        #include <iostream>
        #include <string>
        #include <memory>
        #include "stdint.h"
        #include <stdio.h>
        #include <time.h>
        #include <fcntl.h>
        #include <sys/mman.h>
        
        #include "opencv2/opencv.hpp"
        #include "opencv2/core/core.hpp"
        
        #include <QtCore/QDebug>
        #include <QtCore/QCoreApplication>
        #include <QtConcurrent/QtConcurrent>
        #include <QTcpSocket>
        #include <QTcpServer>
        
        using namespace std;
        using namespace cv;
        
        class MjpegServer : public QObject {
          Q_OBJECT
        public:
          MjpegServer(QObject *parent = 0, int port = 8080);
          ~MjpegServer();
        
        Q_SIGNALS:
        
        public Q_SLOTS:
          void sendFrame(Mat &img);
        
        private Q_SLOTS:
          void newConnection();
          void socketDisconnected();
          void onSocketStateChanged(QAbstractSocket::SocketState);
          void writeHeader();
        
        private:
          QTcpServer* server;
          int port = 8080;
          QMutex socketMutex;
          QList<QTcpSocket *> m_clients;
        };
        
        #endif // MJPEGSERVER_H
        
        1 Reply Last reply
        0
        • Kent-DorfmanK Offline
          Kent-DorfmanK Offline
          Kent-Dorfman
          wrote on last edited by
          #4

          @black_spot1984 said in QTcpSockets added to QList seem to disappear from list:

          private:
          QTcpServer* server;
          int port = 8080;
          QMutex socketMutex;
          QList<QTcpSocket *> m_clients;

          It is bad form to declare member variables, but then not actually initialize them in the constructor.

          I light my way forward with the fires of all the bridges I've burned behind me.

          aha_1980A 1 Reply Last reply
          0
          • Kent-DorfmanK Kent-Dorfman

            @black_spot1984 said in QTcpSockets added to QList seem to disappear from list:

            private:
            QTcpServer* server;
            int port = 8080;
            QMutex socketMutex;
            QList<QTcpSocket *> m_clients;

            It is bad form to declare member variables, but then not actually initialize them in the constructor.

            aha_1980A Offline
            aha_1980A Offline
            aha_1980
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @Kent-Dorfman I'm fully with you, but to be fair the only member that would need an init here is server, which I'd set to nullptr.

            The class-type variables init themself by their ctor.

            Regards

            Qt has to stay free or it will die.

            1 Reply Last reply
            1
            • B Offline
              B Offline
              black_spot1984
              wrote on last edited by black_spot1984
              #6

              Thank you for taking the time to reply. I did change the initializer in the header file. I wouldn't expect that to make a difference. In testing it did not. The output is still:

              No clients
              No clients
              No clients
              No clients
              No clients
              No clients
              Got new MJPEG Connection
              "Clients now connected: 1"
              Writing MJPEG header info
              No clients
              No clients
              ...
              No clients
              

              I can't think why this behavior might be happening.

              1 Reply Last reply
              0
              • B Offline
                B Offline
                black_spot1984
                wrote on last edited by
                #7

                If anyone is interested, the problem turned out to be that I was trying to run this server from outside the main thread. When run from within the main thread this code works.

                Pablo J. RoginaP 1 Reply Last reply
                3
                • B black_spot1984

                  If anyone is interested, the problem turned out to be that I was trying to run this server from outside the main thread. When run from within the main thread this code works.

                  Pablo J. RoginaP Offline
                  Pablo J. RoginaP Offline
                  Pablo J. Rogina
                  wrote on last edited by
                  #8

                  @black_spot1984 glad you found out and thanks for sharing. If your issue is solved, please don't forget to mark your post as such.

                  Upvote the answer(s) that helped you solve the issue
                  Use "Topic Tools" button to mark your post as Solved
                  Add screenshots via postimage.org
                  Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

                  1 Reply Last reply
                  1

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved