Web Sockets
The WebSockets module provides an implementation of the WebSockets protocol for WebSockets clients and servers. It mirrors the Qt CPP module. It allows sending a string and binary messages using a full duplex communication channel. A WebSocket is normally established by making an HTTP connection to the server and the server then “upgrades” the connection to a WebSocket connection.
WebSockets模块为WebSockets客户端和服务器提供WebSockets协议的实现。它反映了Qt CPP模块。它允许使用全双工通信信道发送字符串和二进制消息。WebSocket通常通过与服务器建立HTTP连接来建立,然后服务器将连接“升级”到WebSocket连接。
In Qt/QML you can also simply use the WebSocket and WebSocketServer objects to creates direct WebSocket connection. The WebSocket protocol uses the “ws” URL schema or “wss” for a secure connection.
在Qt/QML中,还可以简单地使用WebSocket和WebSocketServer对象来创建直接的WebSocket连接。WebSocket协议使用“ws”URL模式或“wss”进行安全连接。
You can use the web socket qml module by importing it first.
您可以通过先导入web套接字qml模块来使用它。
import QtWebSockets
WebSocket {
id: socket
}
WS Server
WS服务器
You can easily create your own WS server using the C++ part of the Qt WebSocket or use a different WS implementation, which I find very interesting. It is interesting because it allows connecting the amazing rendering quality of QML with the great expanding web application servers. In this example, we will use a Node JS based web socket server using the ws module. For this, you first need to install node js. Then, create a ws_server
folder and install the ws package using the node package manager (npm).
您可以使用QT的C++模块Qt WebSocket轻松创建自己的WS服务器,或者使用不同的WS实现,这是非常有趣的。这很有趣,因为它可以将QML惊人的渲染质量与不断扩展的web应用服务器连接起来。在本例中,我们将使用ws模块使用基于Node JS的web套接字服务器。为此,首先需要安装node.js。然后,创建一个ws_server
文件夹,并使用node包管理器(npm)安装ws包。
The code shall create a simple echo server in NodeJS to echo our messages back to our QML client.
代码将在NodeJS中创建一个简单的回显服务器,将我们的消息回显到我们的QML客户端。
cd ws_server
npm install ws
The npm tool downloads and installs the ws package and dependencies into your local folder.
npm工具将ws包和依赖项下载并安装到您的本地文件夹中。
A server.js
file will be our server implementation. The server code will create a web socket server on port 3000 and listens to an incoming connection. On an incoming connection, it will send out a greeting and waits for client messages. Each message a client sends on a socket will be sent back to the client.
server.js
文件将是我们的服务器实现。服务器代码将在端口3000上创建一个web套接字服务器,并侦听传入的连接。在传入连接上,它将发送问候并等待客户端消息。客户端在套接字上发送的每条消息都将被发送回客户端。
const WebSocketServer = require('ws').Server
const server = new WebSocketServer({ port : 3000 })
server.on('connection', function(socket) {
console.log('client connected')
socket.on('message', function(msg) {
console.log('Message: %s', msg)
socket.send(msg.toString())
});
socket.send('Welcome to Awesome Chat')
});
console.log('listening on port ' + server.options.port)
You need to get used to the notation of JavaScript and the function callbacks.
您需要习惯JavaScript的符号和函数回调。
WS Client
WS客户端
On the client side, we need a list view to display the messages and a TextInput for the user to enter a new chat message.
在客户端,我们需要一个列表视图来显示消息,还需要一个文本输入,以便用户输入新的聊天消息。
We will use a label with white color in the example.
在本例中,我们将使用白色标签。
// Label.qml
import QtQuick
Text {
color: '#fff'
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
Our chat view is a list view, where the text is appended to a list model. Each entry is displayed using a row of prefix and message label. We use a cell width cw
factor to split the with into 24 columns.
我们的聊天视图是列表视图,文本被附加到列表模型中。每个条目都使用一行前缀和消息标签显示。我们使用单元格宽度cw因子将宽度拆分为24列。
// ChatView.qml
import QtQuick
ListView {
id: root
width: 100
height: 62
model: ListModel {}
function append(prefix, message) {
model.append({prefix: prefix, message: message})
}
delegate: Row {
id: delegate
required property var model
property real cw: width / 24
width: root.width
height: 18
Label {
width: delegate.cw * 1
height: parent.height
text: delegate.model.prefix
}
Label {
width: delegate.cw * 23
height: parent.height
text: delegate.model.message
}
}
}
The chat input is just a simple text input wrapped with a colored border.
聊天输入只是一个用彩色边框包装的简单文本输入。
// ChatInput.qml
import QtQuick
FocusScope {
id: root
property alias text: input.text
signal accepted(string text)
width: 240
height: 32
Rectangle {
anchors.fill: parent
color: '#000'
border.color: '#fff'
border.width: 2
}
TextInput {
id: input
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 4
anchors.rightMargin: 4
color: '#fff'
focus: true
onAccepted: function () {
root.accepted(text)
}
}
}
When the web socket receives a message it appends the message to the chat view. Same applies for a status change. Also when the user enters a chat message a copy is appended to the chat view on the client side and the message is sent to the server.
当web套接字收到消息时,它会将消息附加到聊天视图中。这同样适用于状态更改。此外,当用户输入聊天信息时,会在客户端的聊天视图中添加一份副本,并将该信息发送到服务器。
// ws_client.qml
import QtQuick
import QtWebSockets
Rectangle {
width: 360
height: 360
color: '#000'
ChatView {
id: box
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: input.top
}
ChatInput {
id: input
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
focus: true
onAccepted: function(text) {
print('send message: ' + text)
socket.sendTextMessage(text)
box.append('>', text)
text = ''
}
}
WebSocket {
id: socket
url: "ws://localhost:3000"
active: true
onTextMessageReceived: function (message) {
box.append('<', message)
}
onStatusChanged: {
if (socket.status == WebSocket.Error) {
box.append('#', 'socket error ' + socket.errorString)
} else if (socket.status == WebSocket.Open) {
box.append('#', 'socket open')
} else if (socket.status == WebSocket.Closed) {
box.append('#', 'socket closed')
}
}
}
}
You need first run the server and then the client. There is no retry connection mechanism in our simple client.
您需要先运行服务器,然后运行客户端。在我们的简单客户端中没有重试连接机制。
Running the server
运行服务器
cd ws_server
node server.js
Running the client
运行客户端
cd ws_client
qml ws_client.qml
When entering text and pressing enter you should see something like this.
当输入文本并按enter键时,您应该会看到类似的内容。
示例源码下载