Qt6 QML Book/网络设置/Web Sockets

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客户端。

Qt6 QML Book/网络设置/Web Sockets

cd ws_server
npm install ws

The npm tool downloads and installs the ws package and dependencies into your local folder.

npm工具将ws包和依赖项下载并安装到您的本地文件夹中。

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键时,您应该会看到类似的内容。

Qt6 QML Book/网络设置/Web Sockets

示例源码下载

上一篇:pymongo 聚合搜索


下一篇:PHP(Thinkphp5.1)简单实现微信支付和微信退款