[Qt]Tcp Server simulates Http Server to realize Web real-time monitoring (picture + data)

To realize this function, we need to inherit and rewrite two classes, one is the thread QThread and the other is the Tcp Server. The thread is to separate the data communication from the main thread and avoid blocking. Needless to say, the Tcp Server is used to answer the browser and data communication.

We can look at the header file first. There are two classes:

class HttpSendThread : public QThread
    HttpSendThread(QObject *parent = nullptr):QThread(parent)
    void SetParameters(qintptr socketDescriptor);
    void run();
    qintptr m_socketDescriptor;

protected slots:
    void sockdisconnect();
    bool m_isRunning;
    QTcpSocket *m_socket = nullptr;

class MyTcpServer : public QTcpServer

     MyTcpServer (QObject *parent = 0);
     ~MyTcpServer ();
     qintptr m_socketDescriptor;
     bool status();
     void incomingConnection(qintptr socketDescriptor) ;

     HttpSendThread *m_httpsendthread  = nullptr;


Here are two functions:

void in MyTcpServer    incomingConnection(qintptr socketDescriptor) :

        This function is the slot function triggered when tcpserver is connected. This function is rewritten to obtain the socket descriptor

void SetParameters(qintptr socketDescriptor) in HttpSendThread:

        This function is used to pass the socketDescriptor descriptor so that the thread can use socket to communicate with the browser. For details, see the implementation process below.

cpp file:

The first is the function implementation of MyTcpServer (the constructor can be ignored):

//This function is called when the browser enters by entering IP: PORT
void MyTcpServer::incomingConnection(qintptr socketDescriptor)
    qDebug() << "[OutputPackage]Browser request connection";

    if (!m_httpsendthread  )
        m_httpsendthread  = new HttpSendThread();

		m_socketDescriptor = socketDescriptor;

        //Transfer descriptor


And then   HttpSendThread class:

void HttpSendThread::SetParameters(qintptr socketDescriptor)
    m_socketDescriptor = socketDescriptor;


void HttpSendThread::run()				
    if(m_socket== nullptr)
		qDebug() << "Socket init.";
        m_socket= new QTcpSocket;
        if (!m_socket->setSocketDescriptor(m_socketDescriptor)) {
    //Here, the run function of this thread can normally use this m_socket to communicate
    //do something...


In the run function, we can return the response information to the browser according to the http protocol.

For example:

    //Here is the http protocol response header

    QString http = "HTTP/1.1 200 OK";
    http += QString("Content-Type: text/html; charset=utf-8\r\n\r\n");

    //Here are some page layouts html5+javascript

    QString httphtml = QString("<head >");
    httphtml += QString("<title >luguosheng0110</title>");
    httphtml += QString("<p id='time' align='right'>time</p>");
    httphtml += QString("<center>");
    httphtml += QString("<h1> LUGUOSHENG</h1>");
    httphtml += QString("</center>");

    httphtml += QString("<style type='text/css'>");
    httphtml += QString(".image{");
    httphtml += QString("float:left;width:50%;margin-top:5%;margin-left:2%;}");
    httphtml += QString(".text{");
    httphtml += QString("border: solid #87CEFA;");
    httphtml += QString("height: 570;");
    httphtml += QString("border-width: 1px;");
    httphtml += QString("background: #F0FFFF;");
    httphtml += QString("float:right;width:45%;margin-top:5%;}");
    httphtml += QString("</style>");

    httphtml += QString("</head>");

    httphtml += QString("<div class='text'>");
    httphtml += QString("<center>");

    httphtml += QString("<h3><p id='t1'>The content you selected will be displayed</p></h3>");
    httphtml += QString("</center>");
    httphtml += QString("</div>");

    httphtml += QString("<div id = 'div1' class = 'image' style = 'width:48% ;'>");

    //Focus on this, and we will continue to talk about it next
    httphtml += QString("<img id = 'p1' src = 'data:image/jpg;base64,%1' width = '100%' alt = 'After the camera captures, the screen will be displayed (or the current device is occupied)' />").arg(qhexed);

    httphtml += QString("</div> ");

    //Merge and send to browser
    http += httphtml;	

So what is the effect after sending it? Look at the following:

Because I didn't load the picture data, the picture can't be displayed there (thanks to the rookie tutorial for providing me with a platform to test and verify!).


So how does the picture show?

Here is how to convert QImage to a data type, and then send it to the browser for display in html5 code.

httphtml += QString("<img id = 'p1' src = 'data:image/jpg;base64,%1' width = '100%' alt = 'After the camera captures, the screen will be displayed (or the current device is occupied)' />").

  As you can see from this code, I put the image data into qhexed and then into QString.

Conversion process:

QImage image;
//Put the picture data into the image, and this step is omitted.

QByteArray ba;
QBuffer buf(&ba);
if (!image.save(&buf, "jpg", 6))
	qWarning() << "Jpg image save to buf failed,imageformats folder is missing.";
QByteArray hexed = ba.toBase64();

QString qhexed(hexed);

After this conversion, QImage data is converted into base64 format that can be parsed by the browser and placed in qhexed.

Here, you can actually see the image in the browser.


Then, when you use socket to send html code data to the browser again, you will find that the new data will be appended below instead of refreshing in the original location. Here you need to use javascript+html5 code for replacement, for example:

//Text update:
QString txtdata = "<script>'use strict';";
txtdata += QString("function t1myTimer()");
txtdata += QString("{");
txtdata += QString("document.getElementById('time').innerHTML=Date();");
txtdata += QString("document.getElementById('t1').innerHTML = null;");

QString str_send = "new txt";

txtdata += QString("document.getElementById('t1').innerHTML = decodeURIComponent(escape('%1'));").arg(str_send);
txtdata += QString("}");
txtdata += QString("t1myTimer();");
txtdata += "</script>";

//Image update:
QString imagedata= QString("<script>'use strict';");
imagedata+= QString("function p1myTimer()");
imagedata+= QString("{");
imagedata+= QString("let element = document.getElementById('div1');");
imagedata+= QString("let child = document.getElementById('p1');child.src = null;");
imagedata+= QString("element.removeChild(child);");
imagedata+= QString("let para = document.createElement('img');");
imagedata+= QString("para.setAttribute('id','p1');para.setAttribute('width','100%');");
imagedata+= QString("para.setAttribute('src','data:image/jpg;base64,%1');").arg(qhexed);
imagedata+= QString("let element1 = document.getElementById('div1');");
imagedata+= QString("element1.appendChild(para);");
imagedata+= QString("}");
imagedata+= QString("p1myTimer();");
imagedata+= "</script>";

In this way, the new data will refresh the display in the same position.

Then, when you press F12 in the browser, you will find that the html5 code will always accumulate.

Here you need to use < script > document. Body. InnerHTML = '* * * *'</ Script > replace the original layout code as a whole, and you can empty the existing web page code.

Because the implementation process is complex, I describe it a little messy. If you want to implement it, you still need to test it constantly. I hope it will be useful to you~

Tags: Qt http

Posted on Wed, 06 Oct 2021 10:01:41 -0400 by andrin