"WebSocket connection to 'ws://localhost:12345/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED" 最近在公司实习,使用QT开发需要导出分析报告,选择使用HTML&JS进行页面渲染,那么问题来了,如何实现 C++ QT 和 JavaScript 的通信呢?

前言

WebEngineView是 QT5 新提供的web通信方法,可以实现服务端监听本地端口和客户端实现数据交互。

参考 QT 5.12 官方文档: WebEngineView QML Type

本篇博客将结合官方文档 StandAlone 示例以及自己实际开发中遇到的问题进行分析,如有不当之处欢迎批评指教。

阅读过程中如有排版不适欢迎前往我的博客阅读:

QT5.12 C++与前端JS/HTML实现通信交互​blog.djinguo.com

服务端

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());// setup the QWebSocketServerQWebSocketServer server(QStringLiteral("QWebChannel Standalone Example Server"), QWebSocketServer::NonSecureMode);if (!server.listen(QHostAddress::LocalHost, 12345)) {qFatal("Failed to open web socket server.");return 1;}// wrap WebSocket clients in QWebChannelAbstractTransport objectsWebSocketClientWrapper clientWrapper(&server);// setup the channelQWebChannel channel;QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected,&channel, &QWebChannel::connectTo);// setup the UIDialog dialog;// setup the core and publish it to the QWebChannelCore core(&dialog);channel.registerObject(QStringLiteral("core"), &core);// open a browser window with the client HTML pageQUrl url = QUrl::fromLocalFile(BUILD_DIR "/index.html");QDesktopServices::openUrl(url);dialog.displayMessage(Dialog::tr("Initialization complete, opening browser at %1.").arg(url.toDisplayString()));dialog.show();return app.exec();
}

其实官方文档注释已经很清晰了,首先新建一个APP,然后连接官方提供的 qwebchannel.js 文件(这一步在大型项目中与示例可能不同)。

接着进入正题,开启服务器监听端口,这里是端口12345,如果出错(端口被占用,往往是已经有程序开启监听此端口)则发出错误信息。

然后是声明一个 QT 提供的WebSocketClientWrapper类型,它的内部还包含了一个自定义的类WebSocketTransport,这边就不进行深入剖析了,感兴趣可以自己分析一下它们的代码。

接下来是建立通道连接,声明 QT 提供的QWebChannel对象,利用connect函数将信号和槽进行连接以实现通信连接。

下面的几段代码主要涉及UI界面了,standalone 提供的是服务端使用QT界面,客户端是打开的HTML网页。

接下来的Core个人认为用处不大,因为我们实际开发中使用的是自己的界面类(比如我这次使用的是一个打印报告界面),比较重要的是需要将它发给QWebChannel,

channel.registerObject(QStringLiteral("core"), &core);

双引号里的字符串(名称)需要和JavaScript中使用的相同。

后面就是索引文件,打开这个页面。

最后显示服务端界面。

客户端

官网示例中 JavaScript 代码直接写在HTML中,摘取如下:

<script type="text/javascript" src="./qwebchannel.js"></script>
<script type="text/javascript">//BEGIN SETUPfunction 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]);elsevar baseUrl = "ws://localhost:12345";output("Connecting to WebSocket server at " + baseUrl + ".");var socket = new WebSocket(baseUrl);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.");new QWebChannel(socket, function(channel) {// make core object accessible globallywindow.core = channel.objects.core;document.getElementById("send").onclick = function() {var input = document.getElementById("input");var text = input.value;if (!text) {return;}output("Sent message: " + text);input.value = "";core.receiveText(text);}core.sendText.connect(function(message) {output("Received message: " + message);});core.receiveText("Client connected, ready to send/receive messages!");output("Connected to WebChannel, ready to send/receive messages!");});}}//END SETUP
</script>

其中,8-14行是建立连接,如果连接失败,就会有16-21行的报错,如果一切正常,就会显示"WebSocket connected, setting up QWebChannel.",那么恭喜你,任务已经实现大半了,接下来就是根据 QWebChannel 来进行数据交互实现自己需要的功能了。具体的请参考上面的代码以及 JavaScript 的内容。

遇到的问题

在这次建立通讯开发中我遇到的主要问题就是无法建立连接,也就是开头所写的错误:

"WebSocket connection to 'ws://localhost:12345/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED"

从三个方面进行考虑:本地、服务端、客户端。

一开始以为是监听本地端口被占用等问题,在换了几个端口并且停止本地防火墙后仍然不行,网上的解答是端口关闭,但我在专门开启本地相关端口仍然未解决。

后来靠官方示例排除了是本地原因,因为我开发是使用 Visual Studio 2017 + QT5.11,一开始不能立即很方便地运行官方示例,后来安装了一个QT Creator,发现可以直接选取 example 里面的standalone打开编译成功运行,非常的方便。

那么既然官方示例可以正常运行,看来不是电脑的问题了,将客户端完全换成官方示例的HTML文件,排除客户端。

所以问题肯定出在服务端,也就是QT代码。我又一行一行地研究代码,先努力使我的代码和官方示例尽可能地接近(包括语句顺序等等),梳理了几遍仍然不成功。

最后突然发现standalone的服务端搭建是写在 main 函数中,而我开发的代码是写在打印按钮触发函数之中,在触发结束后便会被释放,也就是说服务端会停止监听端口,难怪客户端无法建立连接!

遂更改之,终于解决问题。(其中还牵扯到一些在哪里声明如何释放内存等问题这里就不一一细说了)

这件事也给我后面开发起到了很大帮助,会更多地关注函数的生命周期,也对C++面向对象有了更深的理解,学习了用智能指针管理对象实现内存释放等等。

最后,感谢公司的二师兄对我的耐心指导!开发路还很长,我还需要向有多年经验的师兄多多学习。

参考链接

QT 5.12 官方文档: WebEngineView QML Type

Qt WebChannel Standalone Example

跟着例子学Qt--2.standalone( C++ QWebChannel server and a HTML/JS client)

flask与js交互的示例代码_QT5.12 C++与前端JavaScript/HTML实现通信交互相关推荐

  1. flask与js交互的示例代码_dapr实战(1):dapr locally环境的搭建和部署官方的Hello world示例...

    引言 dapr是多运行时微服务架构(及机甲架构)的参考实现,关于多运行时微服务架构的介绍,可以参考敖小剑老师的两篇文章: [译]多运行时微服务架构 Mecha:将Mesh进行到底 为了探索dapr的使 ...

  2. flask与js交互的示例代码_Frida Java Hook 详解(安卓9):代码及示例(上)

    Frida Java Hook 详解(安卓9):代码及示例(上) 前言 1.1 FRIDA SCRIPT的"hello world" 1.1.1 "hello world ...

  3. js 单精度浮点数转10进制_确保前端 JavaScript 浮点数精度的四则运算方法

    1 浮点数运算与 IEEE 754 标准 在 JavaScript 中,执行 0.1+0.2,得到的结果却是 0.30000000000000004.这就不得不提到 IEEE 754 标准. IEEE ...

  4. php开发路由器界面,路由器Web页面交互Tips(示例代码)

    路由器Web页面开发中基于cgi形式, 一个页面对应一个c语言文件,如 network-lan.c -> lan_setup.cgi wan.c -> wan.cgi 以network-l ...

  5. python写前端代码_python学习之路前端-JavaScript

    JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果.通常JavaScript脚本是通过嵌入在HTML中来实现 ...

  6. js小学生图区_推荐12个最好的 JavaScript 图形绘制库

    众多周知,图形和图表要比文本更具表现力和说服力.图表是数据图形化的表示,通过形象的图表来展示数据,比如条形图,折线图,饼图等等.可视化图表可以帮助开发者更容易理解复杂的数据,提高生产的效率和 Web  ...

  7. Flask Vue.js全栈开发

    Flask Vue.js全栈开发的 最新完整代码 及使用方式 本系列的最新代码及使用方式将持续更新到: http://www.madmalls.com/blog/post/latest-code/ 1 ...

  8. sex 无需下载_js读取本地json格式文件数据的几种实现方法,内有vue读取json示例代码。...

    方法一:通过getJSON实现 getJSON是jquery提供的读取json格式文件的方法 首先我们将html中引入jquery,可以通过百度CDN引入,代码如下: 然后就可以在script中使用g ...

  9. html制作翻页效果代码,使用原生JS实现滚轮翻页效果的示例代码

    一.滚轮事件 当用户通过鼠标滚轮与页面交互.在垂直方向上滚动页面时,就会触发mousewheel事件,这个事件就是实现全屏切换效果需要用到的.在IE6, IE7, IE8, Opera 10+, Sa ...

最新文章

  1. 二叉树-二叉树的最小深度(递归法)
  2. Python学习之路-12 (递归)
  3. Qt TCP 通讯简单案例
  4. airflow sql_alchemy_conn mysql_搭建AirFlow—— 一段波折后的总结
  5. java 返回值void_Java的返回值voidspeak
  6. 前端学习(1354):集合关联
  7. 这50个思维方法,深刻改变了我的人生
  8. 【举栗子】Docker 容器磁盘占满的几种情况 | CSDN博文精选
  9. 复杂性思维第二版 二、图
  10. Spring、SpringMVC、Shiro面试题
  11. 使用计算机网络时mad的作用,计算机网络基础试题库7
  12. 北大计算机应用基础考研,北大考研辅导班-2021北京大学622计算机应用基础考研经验...
  13. MOEA/D原理及pyton实现
  14. CAD导出PDF线条很粗怎样设置?
  15. jquery获取tr下第某个td的值
  16. 【杂谈】360极速浏览器本地收藏夹的文件在哪里?
  17. Vue3 的 ref 和 reactive 问题
  18. DMOZ重新接受登录申请(转)
  19. mel表达式_Maya Mel基础知识教程 了解运用Mel
  20. 对那些想写个网络音乐播放器、电台玩玩的同学提供一些原料

热门文章

  1. “好串”求解算法优化原理与Python实现
  2. php统计在一个页面停留时间,php记录页面停留时间的代码
  3. mysql中用来取余数的函数是_Excel中一个专门用来评分的函数TRIMMEAN
  4. 两表关联更新 mysql_MySQL多表更新(关联表更新)
  5. 力扣232. 用栈实现队列(JavaScript)
  6. 下面哪个选项不是oracle用户,作业三(有答案)
  7. python制表符_关于ROS运行python的一些问题
  8. layui 如何动态加载局部页面_从输入URL到页面加载的过程?如何由一道题完善自己的前端知识体系!
  9. C++之强制转换const_cast、static_cast、dynamic_cast、reinterpret_cast 、dynamic_cast
  10. mingw c++ 命令行_Mingw-w64在win10下的安装使用