IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> [Qt]Tcp Server模拟Http Server实现Web实时监控(画面+数据) -> 正文阅读

[网络协议][Qt]Tcp Server模拟Http Server实现Web实时监控(画面+数据)

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

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

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

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

class MyTcpServer : public QTcpServer
{
     Q_OBJECT

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

 private:
     HttpSendThread *m_httpsendthread  = nullptr;

 };

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

MyTcpServer中的void??incomingConnection(qintptr socketDescriptor) :

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

HttpSendThread中的void SetParameters(qintptr socketDescriptor):

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

cpp文件:

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

//当浏览器通过输入IP:PORT进入时,该函数被调用
void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "[OutputPackage]Browser request connection";

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

    if(!m_httpsendthread->isRunning())
    {
		m_socketDescriptor = socketDescriptor;

        //传递描述符
        m_httpsendthread->SetParameters(m_socketDescriptor);
        m_httpsendthread->start();
    }

}

然后是?HttpSendThread类:

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)) {
            return;
        }
        connect(m_socket,SIGNAL(disconnected()),this,SLOT(sockdisconnect()));
    }
    
    //到这里,这个线程的run函数就可以正常使用这个m_socket去通信啦
    //do something...

}

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

例如:

    //这里是http的协议应答头

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

    //这里是一些网页布局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% ;'>");

    //重点留意一下这里,下面会继续讲
    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> ");

    //合并一起发给浏览器
    http += httphtml;	
    m_socket->write(http.toUtf8());

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

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

?

那么图片怎么显示呢?

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

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);

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

转换过程:

QImage image;
//把图片数据放到image中,该步省略。

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

QString qhexed(hexed);

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

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

?

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

//文本更新:
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>";

//图像更新:
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>";

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

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

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

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

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-10-08 12:07:15  更:2021-10-08 12:08:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/31 6:35:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码