提交 bd209616 编写于 作者: mahuifa's avatar mahuifa

Merge branch 'Dev'

......@@ -8,7 +8,3 @@ qtHaveModule(webenginewidgets) {
SUBDIRS += channelDemo # 使用QtWebChannel实现QtWeb通信交互(简单示例)
SUBDIRS += channelDemo2 # 使用QtWebChannel实现QtWeb通信交互(进阶功能)
}
......@@ -26,7 +26,6 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
VERSION = 1.0.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
contains(QT_ARCH, i386){ # 使用32位编译器
path = $$PWD/../bin # 程序输出路径
}else{
......@@ -36,7 +35,7 @@ DESTDIR = $$path # 指定编译后的文件存放路径
webFile.path = $$path
webFile.files = $$PWD/hello.html
INSTALLS += webFile # hello.html文件拷贝到path路径下,需要配置Custom Process Step: nmake install才生效
INSTALLS += webFile # hello.html文件拷贝到path路径下,需要配置Custom Process Step: nmake install才生效
# msvc 编译器使用utf-8编码
msvc {
......
......@@ -14,6 +14,8 @@
| channelDemo | 使用QtWebChannel实现Qt与Web通信交互(简单示例) |
| channelDemo2 | 使用QtWebChannel实现Qt与Web通信交互(进阶功能) |
| QtJson | 使用Qt内置json库读写json示例 |
| ChatClient | 使用QWebSocket实现的简单客户端程序 |
| ChatServer | 使用QWebSocketServer实现的简单服务端程序 |
......@@ -100,3 +102,27 @@
> 6. 定义一个带有返回值的槽函数,javascript调用该函数后可以获取【返回值】;
![image-20221216124021490](Web.assets/image-20221216124021490.png)
### 1.7 ChatClient
QWebSocket客户端简单示例
> 1.
> 实现连接、断开连接、数据发送、数据接收显示功能;
![image-20221217210219249](Web.assets/image-20221217210219249.png)
### 1.8 ChatServer
QWebSocketServer服务端简单示例
> 1. 使用QWebSocketServer创建一个服务端,使用【非安全模式】;
> 2. 将所有连接的客户端加入列表,实现服务端同时向所有客户端发送信息;
> 3. 实现将客户端传递过来的信息转发给其它所有客户端;
> 4. 实现在关闭时释放所有客户端功能。
![image-20221217210336065](Web.assets/image-20221217210336065.png)
TEMPLATE = subdirs
SUBDIRS += QtWebExamples \
JsonExamples
JsonExamples \
WebSocketsExamples
#---------------------------------------------------------------------------------------
# @功能: QWebSocket客户端简单示例
# 1、实现连接、断开连接、数据发送、数据接收显示功能;
# @编译器: Desktop Qt 5.12.5 MSVC2017 64bit(也支持其它编译器)
# @Qt IDE D:/Qt/Qt5.12.5/Tools/QtCreator/share/qtcreator
#
# @开发者 mhf
# @邮箱 1603291350@qq.com
# @时间 2022-12-16 21:29:53
# @备注
#---------------------------------------------------------------------------------------
QT += core gui websockets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 定义程序版本号
VERSION = 1.0.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
contains(QT_ARCH, i386){ # 使用32位编译器
DESTDIR = $$PWD/../bin # 程序输出路径
}else{
DESTDIR = $$PWD/../bin64 # 使用64位编译器
}
# msvc 编译器使用utf-8编码
msvc {
QMAKE_CFLAGS += /utf-8
QMAKE_CXXFLAGS += /utf-8
}
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle(QString("QWebSocket客户端简单示例 - V%1").arg(APP_VERSION)); // 设置窗口标题
connect(&m_client, &QWebSocket::connected, this, &Widget::on_connected);
connect(&m_client, &QWebSocket::textFrameReceived, this, &Widget::on_textMessageReceived);
connect(&m_client, &QWebSocket::disconnected, this, &Widget::on_disconnected);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_connected()
{
ui->textEdit->append("连接成功!");
ui->but_connect->setText("断开连接");
}
void Widget::on_disconnected()
{
ui->textEdit->append("断开连接!");
ui->but_connect->setText("连接");
}
/**
* @brief 接收数据
* @param message
*/
void Widget::on_textMessageReceived(const QString &message)
{
ui->textEdit->append(message);
}
/**
* @brief 连接/断开连接控制
*/
void Widget::on_but_connect_clicked()
{
if(ui->but_connect->text() == "连接")
{
m_client.open(QUrl(ui->lineEdit_url->text().trimmed()));
}
else
{
m_client.close();
}
}
/**
* @brief 发送数据
*/
void Widget::on_but_send_clicked()
{
if(m_client.state() == QAbstractSocket::ConnectedState) // 判断是否连接
{
m_client.sendTextMessage(ui->lineEdit_send->text());
}
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QWebSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_connected();
void on_disconnected();
void on_textMessageReceived(const QString &message);
void on_but_connect_clicked();
void on_but_send_clicked();
private:
Ui::Widget *ui;
QWebSocket m_client;
};
#endif // WIDGET_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>520</width>
<height>459</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QTextEdit" name="textEdit"/>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="lineEdit_url">
<property name="text">
<string>ws://localhost:1234</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="but_connect">
<property name="text">
<string>连接</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="lineEdit_send"/>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="but_send">
<property name="text">
<string>发送数据</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
#---------------------------------------------------------------------------------------
# @功能: 实现网页版WebSocket客户端程序
# 1、使用html编写界面css设置样式javascript实现webSocket客户端程序
# 2、将htmlcssjs文件分开编写,便于阅读;
# 4、程序编译后自动将html文件夹拷贝到可执行程序当前路径
# 5、可以直接点击chatClient.html文件运行客户端程序
# 6、也可以在程序编译运行后使用QDesktopServices自动打开html文件
# @编译器: Desktop Qt 5.12.5 MSVC2017 64bit(也支持其它编译器)
# @Qt IDE D:/Qt/Qt5.12.5/Tools/QtCreator/share/qtcreator
#
# @开发者 mhf
# @邮箱 1603291350@qq.com
# @时间 2022-12-17 10:33:31
# @备注
#---------------------------------------------------------------------------------------
QT += core widgets
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNING
SOURCES += main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 定义程序版本号
VERSION = 1.0.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
contains(QT_ARCH, i386){ # 使用32位编译器
path = $$PWD/../bin # 程序输出路径
}else{
path = $$PWD/../bin64 # 使用64位编译器
}
DESTDIR = $$path # 指定编译后的文件存放路径
webFile.path = $$path
webFile.files = $$PWD/html
INSTALLS += webFile # html文件夹拷贝到path路径下,需要配置Custom Process Step: nmake install才生效
button {
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 4px 2px;
cursor: pointer;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
}
button:hover {
box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
}
#textShowId {
/*去掉右下角的斜杠,不允许文本框缩放*/
resize: none;
background: #e6dfdf;
/*设置字体大小*/
font-size: 18px;
/* placeholder位置 提示靠左靠右居中等 */
text-align: left;
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
}
h1 {
font-size: 40px;
color:red;
}
div {
text-align: center; /* 居中 */
}
input {
height: 35px;
background-color: rgb(248, 240, 240);
font-size: 16px;
border: 1px solid rgb(27, 26, 26);
color: black;
outline: none;
padding-left: 15px;
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
}
#nick {
width: 60px;
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket客户端程序</title>
<script src="./chatClient.js"></script>
<link rel="stylesheet" type="text/css" href="chatClient.css">
</head>
<body>
<div>
<h1>WebSocket客户端程序</h1>
<p>
服务端url:<input type="text" id="url" value="ws://localhost:1234">
</p>
<p>
<button id="but_connect" onclick="socketConnectOrDis()">连接</button>
<button id="but_getState" onclick="getState()">WebSocket状态</button>
</p>
<p>
<textarea name="textShow" id="textShowId" cols="60" rows="10" readonly></textarea>
</p>
<p>
<input type="text" id="nick" value="张三" />
<input type="text" id="inputText" onkeydown="if(event.keyCode==13)sendMessage();"/>
<button id="but_send" onclick="sendMessage()" disabled>发送数据</button>
</p>
</div>
</body>
</html>
\ No newline at end of file
// 关于WebSocket的用法可以看【https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket】
var g_client = null; // WebSocket客户端对象
/**
* 控制WebSocket连接或者断开
*/
function socketConnectOrDis()
{
var text = document.getElementById("but_connect").innerHTML;
if(text === "连接")
{
connectWebSocket();
}
else
{
disConnectWebSocket();
}
}
/**
* WebSocket连接
*/
function connectWebSocket()
{
try
{
if(g_client && g_client.readyState === WebSocket.OPEN) // 如果g_client不为空,并且为连接状态
{
g_client.close(); // 关闭连接
}
var url = document.getElementById("url").value;
g_client = new WebSocket(url); // 创建一个WebSocket客户端,并连接
/**
* 连接成功触发事件执行的回调函数
*/
g_client.onopen = function(evt)
{
showMessage("连接成功!");
document.getElementById("but_connect").innerHTML = "断开连接";
document.getElementById("but_send").disabled = false; // 按键使能
}
/**
* 关闭连接触发事件执行的回调函数
*/
g_client.onclose = function(evt)
{
showMessage("关闭连接");
document.getElementById("but_connect").innerHTML = "连接";
document.getElementById("but_send").disabled = true;
}
/**
* 接收到信息的回调函数
*/
g_client.onmessage = function(evt)
{
showMessage("收到:" + evt.data);
}
/**
* 连接失败后的回调函数
*/
g_client.onerror = function(evt)
{
showMessage("Error:" + evt.data);
}
}
catch(exception) // 捕获异常信息
{
showMessage("Error:" + exception);
}
}
/**
* 断开连接
*/
function disConnectWebSocket()
{
if(g_client)
{
g_client.close();
}
}
function getState()
{
if(g_client)
{
var state;
switch(g_client.readyState)
{
case WebSocket.CONNECTING:
{
state = "连接中";
break;
}
case WebSocket.OPEN:
{
state = "已连接";
break;
}
case WebSocket.CLOSING:
{
state = "正在关闭连接";
break;
}
case WebSocket.CLOSED:
{
state = "未连接";
break;
}
default:
{
state = "未知";
break;
}
}
showMessage("客户端当前状态:" + state);
}
else
{
showMessage("客户端未初始化");
}
}
/**
* 显示信息
*/
function showMessage(message)
{
var textShow = document.getElementById("textShowId");
textShow.value += message + "\n"; // 追加信息
textShow.scrollTop = textShow.scrollHeight; // 滚动条显示最下方
}
/**
* 发送信息
*/
function sendMessage()
{
if(g_client != null)
{
var nick = document.getElementById("nick").value; // 获取昵称
var msg = document.getElementById("inputText").value; // 获取发送的数据
var strToSend = nick + ":" + msg;
g_client.send(strToSend);
showMessage("发送:" + strToSend);
}
}
#include <QApplication>
#include <QDesktopServices>
#include <qdir.h>
#include <qurl.h>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
/**
* 使用合适的程序打开url
* QDesktopServices需要使用QApplication才可以执行,
* 否则会报错【QDesktopServices::openUrl: Application is not a GUI application】
*/
qDebug() << QDesktopServices::openUrl(QDir("./html/chatClient.html").absolutePath());
return a.exec();
}
#---------------------------------------------------------------------------------------
# @功能: QWebSocketServer服务端简单示例
# 1、使用QWebSocketServer创建一个服务端,使用【非安全模式】;
# 2、将所有连接的客户端加入列表,实现服务端同时向所有客户端发送信息;
# 3、实现将客户端传递过来的信息转发给其它所有客户端;
# 4、实现在关闭时释放所有客户端功能。
# @编译器: Desktop Qt 5.12.5 MSVC2017 64bit(也支持其它编译器)
# @Qt IDE D:/Qt/Qt5.12.5/Tools/QtCreator/share/qtcreator
#
# @开发者 mhf
# @邮箱 1603291350@qq.com
# @时间 2022-12-16 22:25:06
# @备注
#---------------------------------------------------------------------------------------
QT += core gui websockets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 定义程序版本号
VERSION = 1.0.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
contains(QT_ARCH, i386){ # 使用32位编译器
DESTDIR = $$PWD/../bin # 程序输出路径
}else{
DESTDIR = $$PWD/../bin64 # 使用64位编译器
}
# msvc 编译器使用utf-8编码
msvc {
QMAKE_CFLAGS += /utf-8
QMAKE_CXXFLAGS += /utf-8
}
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle(QString("QWebSocketServer服务端简单示例 - V%1").arg(APP_VERSION)); // 设置窗口标题
m_server = new QWebSocketServer("web服务端", QWebSocketServer::NonSecureMode, this);
connect(m_server, &QWebSocketServer::newConnection, this, &Widget::on_newConnection);
connect(m_server, &QWebSocketServer::closed, this, &Widget::on_closed);
}
Widget::~Widget()
{
// 关闭服务端
if(m_server->isListening())
{
m_server->close();
}
// 关闭所有客户端
qDeleteAll(m_clients.begin(), m_clients.end());
delete ui;
}
/**
* @brief 有新的客户端发起连接
*/
void Widget::on_newConnection()
{
QWebSocket* client = m_server->nextPendingConnection(); // 获取连接成功的客户端
connect(client, &QWebSocket::textMessageReceived, this, &Widget::on_textMessageReceived);
connect(client, &QWebSocket::disconnected, this, &Widget::on_disconnected);
// 将所有客户端加入列表
m_clients << client;
ui->textEdit->append(QString("[%1:%2] 连接成功!").arg(client->peerAddress().toString()).arg(client->peerPort()));
}
/**
* @brief 服务端关闭监听,关闭后不再接收新的客户端的连接请求
*/
void Widget::on_closed()
{
ui->textEdit->append("服务端关闭监听!");
ui->but_listen->setText("开启监听");
}
/**
* @brief 开始监听/关闭服务端监听
*/
void Widget::on_but_listen_clicked()
{
if(!m_server->isListening())
{
bool ret = m_server->listen(QHostAddress::AnyIPv4, 1234);
if(ret)
{
ui->textEdit->append(QString("开始监听:%1").arg(m_server->serverUrl().toString()));
ui->but_listen->setText("停止监听");
}
}
else
{
m_server->close();
}
}
/**
* @brief 向所有连接的客户端发送数据
*/
void Widget::on_but_send_clicked()
{
for(auto client : m_clients)
{
client->sendTextMessage(ui->lineEdit_send->text());
}
}
/**
* @brief 接收信息并将信息转发给所有客户端
* @param message
*/
void Widget::on_textMessageReceived(const QString &message)
{
QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
for(auto client : m_clients)
{
if(client != socket) // 向所有连接的客户端转发信息,除了当前信息的发出者
{
client->sendTextMessage(message);
}
}
ui->textEdit->append(QString("[%1:%2] %3").arg(socket->peerAddress().toString()).arg(socket->peerPort()).arg(message));
}
/**
* @brief 断开连接时移除对应的客户端
*/
void Widget::on_disconnected()
{
QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
for(int i = 0; i < m_clients.count(); ++i)
{
if(m_clients.at(i) == socket)
{
disconnect(socket, &QWebSocket::textMessageReceived, this, &Widget::on_textMessageReceived);
disconnect(socket, &QWebSocket::disconnected, this, &Widget::on_disconnected);
m_clients.removeAt(i);
break;
}
}
ui->textEdit->append(QString("[%1:%2] 断开连接!").arg(socket->peerAddress().toString()).arg(socket->peerPort()));
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QWebSocketServer>
#include <QtWebSockets>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_newConnection();
void on_closed();
void on_textMessageReceived(const QString &message);
void on_disconnected();
void on_but_listen_clicked();
void on_but_send_clicked();
private:
Ui::Widget *ui;
QWebSocketServer* m_server = nullptr;
QList<QWebSocket*> m_clients;
};
#endif // WIDGET_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>573</width>
<height>446</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QTextEdit" name="textEdit"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="but_listen">
<property name="text">
<string>开启监听</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_send"/>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="but_send">
<property name="text">
<string>发送数据</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
TEMPLATE = subdirs
SUBDIRS += ChatClient # 使用QWebSocket实现的简单客户端程序
SUBDIRS += ChatServer # 使用QWebSocketServer实现的简单服务端程序
SUBDIRS += ChatClientHtml # 前端网页版本WebSocket客户端程序(html+css+javascript实现
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册