摘要
在QT中和HTML进行通信通过websocket
转载请声明原创地址哟。
PS:对这块不熟有错误请指出
这换行有毒,谅解。
概述: C++和HTML通过websocket通信,通过官方的qwebchannel.js实现。 C++和HTML共用一个对象并以此进行通信 C++通知HTML:通过信号 HTML通知C++:直接调用其函数 核心类:QWebChannel QT版本:5.6
首先:例子是使用QT自带的例子 大致组成: WebSocketClientWrapper:一个包装为了将WebSocketTransport作为信号参数让QWebChannel能接受到 WebSocketTransport:关键点之一,继承自QWebChannelAbstractTransport Dialog:用于通信的对象 index.html:演示用的html文件 qwebchannel.js:关键点之一,本人是搜索了整个QT找出来的有3个同名文件大小有些区别,具体内容没看过有哪些区别,看目录也就应该知道选哪个了,没有的话运行会报错的,功能:类似管理吧,即存储着注册对象的方法,信号之类的,当然要处理收到的信息后才能存下来。
代码分析: PS:C++是服务端,HTML是客户端 本人:先把其他的大致看一下然后从main出发 main.cpp
-
#include "qwebchannel.h"
-
#include <QApplication>
-
#include <QDialog>
-
#include <QVariantMap>
-
#include <QDesktopServices>
-
#include <QUrl>
-
#include <QDir>
-
#include <QFileInfo>
-
#include <QtWebSockets/QWebSocketServer>
-
#include "../shared/websocketclientwrapper.h"
-
#include "../shared/websockettransport.h"
-
#include "ui_dialog.h"
-
class Dialog : public QObject
-
{
-
Q_OBJECT
-
public:
-
explicit Dialog(QObject *parent = 0)
-
: QObject(parent)
-
{
-
ui.setupUi(&dialog);
-
dialog.show();
-
connect(ui.send, SIGNAL(clicked()), SLOT(clicked()));
-
}
-
void displayMessage(const QString &message)
-
{
-
ui.output->appendPlainText(message);
-
}
-
signals:
-
void sendText(const QString &text);
-
public slots:
-
void receiveText(const QString &text)
-
{
-
displayMessage(tr("Received message: %1").arg(text));
-
}
-
private slots:
-
void clicked()
-
{
-
const QString text = ui.input->text();
-
if (text.isEmpty()) {
-
return;
-
}
-
emit sendText(text);
-
displayMessage(tr("Sent message: %1").arg(text));
-
ui.input->clear();
-
}
-
private:
-
QDialog dialog;
-
Ui::Dialog ui;
-
};
-
int main(int argc, char** argv)
-
{
-
QApplication app(argc, argv);
-
QFileInfo jsFileInfo(QDir::currentPath() + "/qwebchannel.js");
-
if (!jsFileInfo.exists())
-
QFile::copy(":/qtwebchannel/qwebchannel.js",jsFileInfo.absoluteFilePath());
-
//这只是为了能把qwebchannel.js放到指定目录能让index.html找到,在我这然并卵.手动复制
-
QWebSocketServer server(QStringLiteral("QWebChannel Standalone Example Server"), QWebSocketServer::NonSecureMode);
-
//创建webSocket服务端,第二个参数应该是和关闭防火墙类似的操作,不进行安全检测
-
if (!server.listen(QHostAddress::LocalHost, 12345)) {
-
qFatal("Failed to open web socket server.");
-
return 1;
-
}
-
//创建完后肯定要绑定啦,地址端口号要和HTML中的一样
-
WebSocketClientWrapper clientWrapper(&server);
-
/* 为了能将接受到的新连接的套接字包装成WebSocketTransport用信号传递给
-
** QWebChannel的void QWebChannel::connectTo(QWebChannelAbstractTransport *transport)
-
** 而接受参数正好是QWebChannelAbstractTransport,WebSocketTransport就是它的子类
-
*/
-
QWebChannel channel;
-
QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected,
-
&channel, &QWebChannel::connectTo);
-
/*
-
** 当有新连接即html端打开,serve将获得与之相连的新socket,接着触发WebSocketClientWrapper槽
-
** 将socket作为WebSocketTransport参数实例化这个对象,然后作为信号参数传递给QWebChannel
-
** QWebChannel就获得了与html通话的能力
-
*/
-
Dialog dialog;
-
channel.registerObject(QStringLiteral("dialog"), &dialog);//注册后能在HTML中使用
-
//感觉就是这了,将Dialog的信号,函数等信息发给qwebchannel让其处理
-
QUrl url = QUrl::fromLocalFile(BUILD_DIR "/index.html");
-
QDesktopServices::openUrl(url);
-
//这两句只是自动打开html而已,可以手动打开的哟
-
//为了照顾下面那一行代码才没有将其删除
-
dialog.displayMessage(QObject::tr("Initialization complete, opening browser at %1.").arg(url.toDisplayString()));
-
return app.exec();
-
}
-
#include "main.moc"
-
/*
-
* 一般情况下,你的类会单独写,一个 ***.h, 一个 ***.cpp 。 类的定义在 头文件中,qmake可以调用moc自动处理(生成moc_***.h)并自动包含。
-
但你要是偷懒,比如把main函数和类的定义及实现都放到一个文件内,比如取名 main.cpp ,这时就不那么走运了,moc处理后生成 同名 的 .moc 文件,但这时你必须自己包含它了。
-
*/
服务端小结: 1.准备serve,绑定地址端口 2.收到链接后交给QWebChannel 3.准备对象用于被注册(感觉随便啦,有信号,有方法就行)PS:应该是C++和HTML共用一个实例 只是C++是直接调用,HTML是通过QWebChannel调用
服务端暂时这样了,接下来看看客户端吧 index.html
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
<script type="text/javascript" src="./qwebchannel.js"></script>
-
<script type="text/javascript">
-
//BEGIN SETUP
-
function output(message)
-
{
-
var output = document.getElementById("output");
-
output.innerHTML = output.innerHTML + message + "\n";
-
}
-
//为了在打印信息而准备的方法
-
window.onload = function() {
-
if (location.search != "")
-
var baseUrl = (/[?&]webChannelBaseUrl=([A-Za-z0-9\-:/\.]+)/.exec(location.search)[1]);
-
else
-
var baseUrl = "ws://localhost:12345";
-
output("Connecting to WebSocket server at " + baseUrl + ".");
-
var socket = new WebSocket(baseUrl);//创建一个Socket实例,连接到服务器
-
//几个事件的绑定
-
socket.onclose = function()
-
{
-
console.error("web channel closed");
-
};
-
socket.onerror = function(error)
-
{
-
console.error("web channel error: " + error);
-
};
-
socket.onopen = function()// 连接成功后触发
-
{
-
output("WebSocket connected, setting up QWebChannel.");
-
//将socket交给qwebchannel.js,处理完后回调
-
new QWebChannel(socket, function(channel) {
-
// make dialog object accessible globally
-
window.dialog = channel.objects.dialog;
-
//应该是设置全局对象吧,objects里应该就存放着注册的对象
-
document.getElementById("send").onclick = function() {
-
var input = document.getElementById("input");
-
var text = input.value;
-
if (!text) {
-
return;
-
}
-
output("Sent message: " + text);
-
input.value = "";
-
dialog.receiveText(text);
-
}
-
//HTML的send按钮的点击事件处理
-
dialog.sendText.connect(function(message) {
-
output("Received message: " + message);
-
});
-
//C++调用sendText时会使用到这里的匿名函数
-
dialog.receiveText("Client connected, ready to send/receive messages!");
-
//HTML直接调用函数
-
output("Connected to WebChannel, ready to send/receive messages!");
-
});
-
}
-
}
-
//END SETUP
-
</script>
-
<style type="text/css">
-
html {
-
height: 100%;
-
width: 100%;
-
}
-
#input {
-
width: 400px;
-
margin: 0 10px 0 0;
-
}
-
#send {
-
width: 90px;
-
margin: 0;
-
}
-
#output {
-
width: 500px;
-
height: 300px;
-
}
-
</style>
-
</head>
-
<body>
-
<textarea id="output"></textarea><br />
-
<input id="input" /><input type="submit" id="send" value="Send" onclick="javascript:click();" />
-
</body>
-
</html>
客户端小结: 1.链接到服务器,并写好对应事件的绑定 2.new QWebChannel 3.qwebchannel.js会帮我们处理的
最后注意: 这些也是得有的在WebSocketTransport中
不要随便删。JSON也是要的传输的是JSON格式的数据
JS方面的能力比较渣,有错请喷,想深入了解的话可以去看源码,能力不足看晕了,不过这个qwebchannel.js倒是可以看一下,才400来行。 还是不太熟悉直接在参数里写函数,总觉得别扭,怪怪的。
FROM:https://my.oschina.net/LiangJYue/blog/668427