当前位置:   article > 正文

[Qt]Tcp Server模拟Http Server实现Web实时监控(画面+数据)_tcp模拟http

tcp模拟http

实现这个功能我们需要继承重写两个类,一个是线程QThread,一个是Tcp Server,线程是为了把数据通信和主线程分开,避免阻塞,Tcp Server就不用说了,用来应答浏览器及数据通讯。

我们可以先看头文件,两个类:

  1. class HttpSendThread : public QThread
  2. {
  3. Q_OBJECT
  4. public:
  5. HttpSendThread(QObject *parent = nullptr):QThread(parent)
  6. {
  7. }
  8. ~HttpSendThread(){}
  9. void SetParameters(qintptr socketDescriptor);
  10. void run();
  11. qintptr m_socketDescriptor;
  12. protected slots:
  13. void sockdisconnect();
  14. private:
  15. bool m_isRunning;
  16. QTcpSocket *m_socket = nullptr;
  17. };
  18. class MyTcpServer : public QTcpServer
  19. {
  20. Q_OBJECT
  21. public:
  22. MyTcpServer (QObject *parent = 0);
  23. ~MyTcpServer ();
  24. qintptr m_socketDescriptor;
  25. bool status();
  26. protected:
  27. void incomingConnection(qintptr socketDescriptor) ;
  28. private:
  29. HttpSendThread *m_httpsendthread = nullptr;
  30. };

在这里介绍一下两个函数:

MyTcpServer中的void  incomingConnection(qintptr socketDescriptor) :

        这个函数是当tcpserver被连接时触发的槽函数,重写这个函数主要是为了获得socketDescriptor这个描述符

HttpSendThread中的void SetParameters(qintptr socketDescriptor):

        这个函数就是用来传递socketDescriptor描述符,使得线程中能够使用socket进行和浏览器通讯,具体可以看下面的实现过程。

cpp文件:

首先是MyTcpServer的函数实现(构造函数可忽略):

  1. //当浏览器通过输入IP:PORT进入时,该函数被调用
  2. void MyTcpServer::incomingConnection(qintptr socketDescriptor)
  3. {
  4. qDebug() << "[OutputPackage]Browser request connection";
  5. if (!m_httpsendthread )
  6. {
  7. m_httpsendthread = new HttpSendThread();
  8. }
  9. if(!m_httpsendthread->isRunning())
  10. {
  11. m_socketDescriptor = socketDescriptor;
  12. //传递描述符
  13. m_httpsendthread->SetParameters(m_socketDescriptor);
  14. m_httpsendthread->start();
  15. }
  16. }

然后是 HttpSendThread类:

  1. void HttpSendThread::SetParameters(qintptr socketDescriptor)
  2. {
  3. m_socketDescriptor = socketDescriptor;
  4. }
  5. void HttpSendThread::run()
  6. {
  7. if(m_socket== nullptr)
  8. {
  9. qDebug() << "Socket init.";
  10. m_socket= new QTcpSocket;
  11. if (!m_socket->setSocketDescriptor(m_socketDescriptor)) {
  12. return;
  13. }
  14. connect(m_socket,SIGNAL(disconnected()),this,SLOT(sockdisconnect()));
  15. }
  16. //到这里,这个线程的run函数就可以正常使用这个m_socket去通信啦
  17. //do something...
  18. }

在run函数中,我们就可以按照http的协议给浏览器返回应答信息啦。

例如:

  1. //这里是http的协议应答头
  2. QString http = "HTTP/1.1 200 OK";
  3. http += QString("Content-Type: text/html; charset=utf-8\r\n\r\n");
  4. //这里是一些网页布局html5+javascript
  5. QString httphtml = QString("<head >");
  6. httphtml += QString("<title >luguosheng0110</title>");
  7. httphtml += QString("<p id='time' align='right'>time</p>");
  8. httphtml += QString("<center>");
  9. httphtml += QString("<h1> LUGUOSHENG</h1>");
  10. httphtml += QString("</center>");
  11. httphtml += QString("<style type='text/css'>");
  12. httphtml += QString(".image{");
  13. httphtml += QString("float:left;width:50%;margin-top:5%;margin-left:2%;}");
  14. httphtml += QString(".text{");
  15. httphtml += QString("border: solid #87CEFA;");
  16. httphtml += QString("height: 570;");
  17. httphtml += QString("border-width: 1px;");
  18. httphtml += QString("background: #F0FFFF;");
  19. httphtml += QString("float:right;width:45%;margin-top:5%;}");
  20. httphtml += QString("</style>");
  21. httphtml += QString("</head>");
  22. httphtml += QString("<div class='text'>");
  23. httphtml += QString("<center>");
  24. httphtml += QString("<h3><p id='t1'>The content you selected will be displayed</p></h3>");
  25. httphtml += QString("</center>");
  26. httphtml += QString("</div>");
  27. httphtml += QString("<div id = 'div1' class = 'image' style = 'width:48% ;'>");
  28. //重点留意一下这里,下面会继续讲
  29. 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);
  30. httphtml += QString("</div> ");
  31. //合并一起发给浏览器
  32. http += httphtml;
  33. m_socket->write(http.toUtf8());

那么发过去之后的效果是怎样的呢?看下面:

由于我没有加载图片数据,所以图片那里不能显示(在这里感谢菜鸟教程提供平台给我测试验证!)。

 

那么图片怎么显示呢?

这里介绍一下如何把QImage转换到某个数据类型,然后放在html5代码中一起发送到浏览器显示。

  1. 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)' />").
  2. arg(qhexed);

 从这段代码可以看到,我是把图片数据放到qhexed中,然后放到QString中。

转换过程:

  1. QImage image;
  2. //把图片数据放到image中,该步省略。
  3. QByteArray ba;
  4. QBuffer buf(&ba);
  5. buf.open(QIODevice::WriteOnly);
  6. if (!image.save(&buf, "jpg", 6))
  7. {
  8. qWarning() << "Jpg image save to buf failed,imageformats folder is missing.";
  9. }
  10. QByteArray hexed = ba.toBase64();
  11. QString qhexed(hexed);

经过这段转换,QImage数据就转成了浏览器可以解析的base64格式了,放在qhexed中。

到这里,其实就可以在浏览器看到图像了。

 

然后,当你再次使用socket给浏览器发送html代码数据时,你会发现新数据会追加在下面,而不是在原来的位置刷新。这里就需要用到javascript+html5代码进行替换,比如:

  1. //文本更新:
  2. QString txtdata = "<script>'use strict';";
  3. txtdata += QString("function t1myTimer()");
  4. txtdata += QString("{");
  5. txtdata += QString("document.getElementById('time').innerHTML=Date();");
  6. txtdata += QString("document.getElementById('t1').innerHTML = null;");
  7. QString str_send = "new txt";
  8. txtdata += QString("document.getElementById('t1').innerHTML = decodeURIComponent(escape('%1'));").arg(str_send);
  9. txtdata += QString("}");
  10. txtdata += QString("t1myTimer();");
  11. txtdata += "</script>";
  12. //图像更新:
  13. QString imagedata= QString("<script>'use strict';");
  14. imagedata+= QString("function p1myTimer()");
  15. imagedata+= QString("{");
  16. imagedata+= QString("let element = document.getElementById('div1');");
  17. imagedata+= QString("let child = document.getElementById('p1');child.src = null;");
  18. imagedata+= QString("element.removeChild(child);");
  19. imagedata+= QString("let para = document.createElement('img');");
  20. imagedata+= QString("para.setAttribute('id','p1');para.setAttribute('width','100%');");
  21. imagedata+= QString("para.setAttribute('src','data:image/jpg;base64,%1');").arg(qhexed);
  22. imagedata+= QString("let element1 = document.getElementById('div1');");
  23. imagedata+= QString("element1.appendChild(para);");
  24. imagedata+= QString("}");
  25. imagedata+= QString("p1myTimer();");
  26. imagedata+= "</script>";

这样,新数据就会在同样的位置去刷新显示了。

然后,当你在浏览器按F12时,你就会发现html5代码会一直累加一直累加。

这里就需要用到<script>document.body.innerHTML = ' **** ';</script>进行整体替换,把最初的布局代码重新发一遍,就可以实现清空现有的网页代码。

由于实现过程比较复杂,所以我描述得也有点乱,如果你想实现,感觉还是需要不断测试。希望对你们有用~

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号