Qt:用WebSocket构建QML和C++之间的桥梁

前言

WebSocket,作为一个全双工的网络通讯协议,正在慢慢的被各大开发框架和语言接受。

之前有说过Qt在5.10新出了WebGL的platform,连接如下:

http://blog.csdn.net/wsj18808050/article/details/78791001

其中在浏览器和程序之间,负担着大量数据传递,就是WebSocket。

今天就来说下QML如何通过WebSocket和C++交互。

关于WebSocket的相关知识,以及相比其它通讯协议优劣点,这里不再累述,有兴趣的同学可以自行搜索下。


信号和槽?还是WebSocket

一般来说,使用QML开发当程序,都是通过信号和槽,与C++交互。

这时候问题就来了,如果需求是要跨进程或者跨设备,那这种传统方法就不可行。

ps:这里不讨论Qt Remote Object

通常我们的做法是在C++写一个接口,把通讯协议,比如说TCP或者消息队列,封装好,然后再注册一个类到QML,再在QML中调用这个注册过去的类以及接口。

这一过程繁琐,涉及的接口多,造成诸多困扰和不便。

另外如果是自己根据一些底层协议搞,比如说根据传输层的TCP造应用层的轮子,那问题更多了,相信造过轮子的人都有感受。

即使是使用HTTP,也会有性能、网络延迟和反向通知(服务器主动通知客户端)等问题。

因此,就出现了WebSocket,在一定范围内,来解决这一系列的问题。


使用

直接上代码,展示如何使用WebSocket

C++代码(服务端):

QWebSocketServer server( "MyServer", QWebSocketServer::NonSecureMode ); // 实例化一个WebSocket服务端
QObject::connect( &server, &QWebSocketServer::newConnection, [ &server ]() // 连接信号,这里使用lambda的方式,以简化代码
{
    // 当接收到一个新连接时
    auto webSocket = server.nextPendingConnection();
    qDebug() << "newConnection:" << webSocket;

    QObject::connect( webSocket, &QWebSocket::textMessageReceived, [ webSocket ](const QString &message) // 连接信号,这里使用lambda的方式,以简化代码
    {
        // 当连接收到数据时
        qDebug() << "server textMessageReceived:" << message;
        webSocket->sendTextMessage( "Please enjoy WebSocket" );
    } );
} );
qDebug() << "listen:" << server.listen( QHostAddress::Any, 18546 ); // 开始监听

这几行代码,就可以实现一个简单的WebSocket服务端的应答机制

使用方法和QTcpServer如出一辙,就是扩展了一些接口和属性。

QML代码(客户端):

WebSocket {
    id: webSocket
    url: "ws://127.0.0.1:18546" // url表示目标的地址、端口、path和query这些
    active: true // active表示开启这个连接

    onStatusChanged: {
        // 监听socket状态变化

        if ( status === WebSocket.Open )
        {
            // Open状态表示连接已经打开,立即发送一个"Hello WebSocket"

            print( "WebSocket is opened" );
            webSocket.sendTextMessage( "Hello WebSocket" );
        }
    }

    onTextMessageReceived: {
        // 监听收到的数据,收到后通过print打印到控制台

        print( "onTextMessageReceived:", message );
    }
}

也只需要这几行代码,就可以在QML中简单的操作WebSocket完成一次发送和接收操作。

如果运行正常,那么C++和QML依次运行后,控制台就会有如下打印:

qml: WebSocket is opened
qml: onTextMessageReceived: Please enjoy WebSocket

path & query

和HTTP请求一样,WebSocket可以在url中加入path和query,让请求更规范和简洁。

例如现在有一个聊天室的WebSocket请求,进入到聊天房间1,接受所有类型的消息,那url就可以这样写:

ws://127.0.0.1:18546/chatroom/1?filter=all

在C++端,可以这样解析:

qDebug() << "path:" << webSocket->request().url().path();
qDebug() << "query:" << webSocket->request().url().query();

C++端,打印内容如下:

path: "/chatroom/1"
query: "filter=all"

总结

WebSocket与常见的HTTP和TCP相比,他相当于结合了二者的优点,既能够方便快捷的使用,又能保持长连接、低延迟和双向通讯等特点。

但是,WebSocket必然不是一个万能协议,不是说他出现,就直接干掉HTTP和TCP了,最终技术选型,还是要按照项目实际需求来。


Qt官方文档

http://doc.qt.io/qt-5/qwebsocketserver.html

https://doc.qt.io/qt-5/qml-qtwebsockets-websocket.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,以下是用Qt写出WebSocket服务端和客户端的代码,已经加上注释: 服务端代码: #include <QtCore/QCoreApplication> #include <QtWebSockets/QWebSocketServer> #include <QtWebSockets/QWebSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QWebSocketServer server(QStringLiteral("WebSocket Server"), QWebSocketServer::NonSecureMode); if (!server.listen(QHostAddress::Any, 1234)) { // 监听所有IP地址,端口号为1234 qFatal("Failed to listen on port 1234."); return 1; } QObject::connect(&server, &QWebSocketServer::newConnection, [&server]() { QWebSocket *socket = server.nextPendingConnection(); QObject::connect(socket, &QWebSocket::textMessageReceived, [socket](const QString &message) { qDebug() << "Received message:" << message; socket->sendTextMessage(QStringLiteral("Echo: %1").arg(message)); // 回复客户端 }); }); qDebug() << "WebSocket server started on port 1234."; return a.exec(); } 客户端代码: #include <QtCore/QCoreApplication> #include <QtWebSockets/QWebSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QWebSocket socket; QObject::connect(&socket, &QWebSocket::connected, [&socket]() { qDebug() << "Connected to server."; socket.sendTextMessage(QStringLiteral("Hello, server!")); // 发送消息给服务端 }); QObject::connect(&socket, &QWebSocket::textMessageReceived, [](const QString &message) { qDebug() << "Received message:" << message; }); socket.open(QUrl(QStringLiteral("ws://localhost:1234"))); // 连接到服务端 return a.exec(); } 希望这个代码能够帮到你。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值