Qt WebSocket的基本使用

(只是作为个人纪录,如果你要使用的话在 Qt 示例里搜 websocket 看官方 Demo 就行了,代码量不多)

0.前言

(参见Qt文档说明)WebSockets 是一种通过单个 TCP 连接提供全双工通信信道的 web 技术。2011年,IETF 将 WebSocket 协议标准化为 RFC 6455 。Qt 提供的 QWebSocket 既可以用于客户端应用程序,也可以用于服务端应用程序,接口大部分和 QTcpSocket 一致。

QWebSocket 当前不支持 WebSocket 扩展和 WebSocket 子协议,仅支持 WebSocket 协议的版本13 (如 RFC 6455 中所述)。

1.QWebSocket与QWebSocketServer的基本使用

(完整代码链接,包含 Qt Server/Client 和 HTML Client:https://github.com/gongjianbo/MyTestCode/tree/master/Qt/QtWebSocketDemo

要使用 Qt 的 WebSocket 模块,先在 pro 文件中加上 websockets:

QT += websockets

这是我 Demo 界面:

对于服务端,需要用到 QWebSocketServer 和 QWebSocket 两个类。创建 Server 对象后,使用 listen 函数监听端口,新的连接到来时,触发 newConnection 信号,这时候才槽函数种使用 nextPendingConnection 函数获取到这个 Socket 连接。

主要实现代码:

WebSocketServer::WebSocketServer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WebSocketServer)
{
    ui->setupUi(this);

    //构造:QWebSocketServer(const QString& serverName,QWebSocketServer::SslMode secureMode,QObject *parent=nullptr)
    //使用给定的serverName构造一个新的QWebSocketServer。
    //该服务器名称将在HTTP握手阶段被用来识别服务器。它可以为空,此时不会将服务器名称发送给客户端。
    //SslMode指示服务器是通过wss(SecureMode)还是ws(NonSecureMode)运行
    //QWebSocketServer::SecureMode服务器以安全模式运行(通过wss)
    //QWebSocketServer::NonSecureMode服务器以非安全模式运行(通过ws)
    server=new QWebSocketServer("Server",QWebSocketServer::NonSecureMode,this);

    //服务器监听
    ui->btnSend->setEnabled(false);
    connect(ui->btnListen,&QPushButton::clicked,[this](){
        if(ui->btnListen->text()!="Listen"){
            ui->btnSend->setEnabled(false);
            ui->btnListen->setText("Listen");
            clearClient();
            server->close();
        }else{
            QHostAddress address;
            if(ui->editAddress->text()=="Any"){
                address=QHostAddress::Any;
            }else{
                address=QHostAddress(ui->editAddress->text());
            }
            //判断是否连接上
            if(server->listen(address,ui->editPort->text().toUInt())){
                ui->btnSend->setEnabled(true);
                ui->btnListen->setText("Dislisten");
            }
        }
    });
    //新的连接进来
    connect(server,&QWebSocketServer::newConnection,this,&WebSocketServer::onNewConnection);
    //发送消息给客户端
    connect(ui->btnSend,&QPushButton::clicked,[this](){
        if(!ui->editSend->toPlainText().isEmpty())
            emit sendMessage(ui->editSend->toPlainText());
    });
}

WebSocketServer::~WebSocketServer()
{
    clearClient();
    server->close();
    delete ui;
}

void WebSocketServer::clearClient()
{
    for(int i=clientList.count()-1;i>=0;i--)
    {
        //qDebug()<<i;
        clientList.at(i)->disconnect();
        clientList.at(i)->close();
    }
    qDeleteAll(clientList);
    clientList.clear();
}

void WebSocketServer::onNewConnection()
{
    QWebSocket *socket=server->nextPendingConnection();
    if(!socket)
        return;
    clientList.push_back(socket);
    ui->editRecv->append(QString("[New Connect] Address:%1  Port:%2")
                         .arg(socket->peerAddress().toString())
                         .arg(socket->peerPort()));

    //收到消息
    connect(socket,&QWebSocket::textMessageReceived,[this](const QString &msg){
        ui->editRecv->append(msg);
    });
    //发送消息
    connect(this,&WebSocketServer::sendMessage,socket,&QWebSocket::sendTextMessage);
    //断开连接,释放
    connect(socket,&QWebSocket::disconnected,[this,socket](){
        clientList.removeAll(socket);
        socket->deleteLater();
    });
}

 对于客户端,好像没有指定 bind 自己端口的接口,只能指定服务端的 Url。通过 open 函数连接服务端的 Url ,使用 close 关闭连接。数据到来的时候有 textMessageReceived 和 binaryMessageReceived 等信号触发,也可以调用 sendTextMessage 或 sendBinaryMessage 发送数据。

主要实现代码:

WebSocketClient::WebSocketClient(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WebSocketClient)
{
    ui->setupUi(this);

    //构造:QWebSocket(const QString &origin = QString(), QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest, QObject *parent = nullptr)
    //使用给定的源,要使用的协议版本和parent创建一个新的QWebSocket 。
    client=new QWebSocket;
    client->setParent(this);

    //连接服务端
    connect(ui->btnOpen,&QPushButton::clicked,[this](){
        if(ui->btnOpen->text()!="Open"){
            client->close();
        }else{
            client->open(QUrl(ui->editUrl->text()));
        }
    });
    //连接结果
    ui->btnSend->setEnabled(false);
    connect(client,&QWebSocket::connected,[this](){
        ui->btnSend->setEnabled(true);
        ui->btnOpen->setText("Close");
        ui->footLabel->setText(QString("Address:%1  Port:%2")
                               .arg(client->localAddress().toString())
                               .arg(client->localPort()));
        qDebug()<<"connected";
    });
    connect(client,&QWebSocket::disconnected,[this](){
        ui->btnSend->setEnabled(false);
        ui->btnOpen->setText("Open");
        qDebug()<<"disconnected";
    });
    //发送数据
    connect(ui->btnSend,&QPushButton::clicked,[this](){
        if(!ui->editSend->toPlainText().isEmpty())
            client->sendTextMessage(ui->editSend->toPlainText());
    });
    //接收数据
    connect(client,&QWebSocket::textMessageReceived,[this](const QString &msg){
        ui->editRecv->append(msg);
    });
}

WebSocketClient::~WebSocketClient()
{
    //结束的时候没关会异常
    client->close();
    delete ui;
}

网页 WebSocket 客户端的简单 Demo: 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Qt WebSocket Demo</title>
</head>

<body>
    <input type="text" id="edit_url" value="ws://localhost:12345" />
    <input type="button" id="btn_open" value="Open" onclick="doOpen()" />
    <br />
    <p>Recv:</p>
    <br />
    <textarea id="edit_recv" cols="50" rows="10"></textarea>
    <br />
    <p>Send:</p>
    <br />
    <textarea id="edit_send" cols="50" rows="10">Hello</textarea>
    <br />
    <input type="button" value="Send" onclick="doSend()" />
    <script>
        var edit_url = document.getElementById("edit_url");
        var btn_open = document.getElementById("btn_open");
        var edit_recv = document.getElementById("edit_recv");
        var edit_send = document.getElementById("edit_send");

        var client = null;

        function doOpen() {
            console.log("open")
            if (!("WebSocket" in window)) {
                //不支持WebSocket
                return;
            }
            if (client === null) {
                client = new WebSocket(edit_url.value);

                client.onopen = function () {
                    btn_open.value = "Close";
                }
                //收到数据后追加到尾巴上
                client.onmessage = function (event) {
                    edit_recv.value += String(event.data);
                }
                client.onclose = function () {
                    client = null;
                    btn_open.value = "Open";
                }
            } else {
                client.close();
                client = null;
            }
        }

        function doSend() {
            console.log("send")
            if (client === null)
                return;
            client.send(edit_send.value);
        }
    </script>
</body>

</html>

2.使用带SSL的WebSocket(略,暂时没用到)

3.提示[LspTrace]ReadAccConfig returns false!

Windows 命令行(管理员权限)输入 netsh winsock reset,等出现提示后重启电脑。

参考:https://blog.csdn.net/zxl_1996/article/details/86333945

Netsh winsock reset是一个命令提示程序,用于将winsock目录重置为默认设置或清除状态。如有时候上不了网或者网络出现问题经常用到它,简单地理解就是:重置程序通过操作系统链接网络的入口点。虽然使用此命令可以恢复网络连接,也应谨慎使用,因为可能需要重新安装LSPLSP: layered service privider 分层服务提供商。LSP是TCP/IP等协议的接口。

参考:https://baijiahao.baidu.com/s?id=1621092219410327325&wfr=spider&for=pc

4.参考

Qt 文档:https://doc.qt.io/qt-5/qwebsocket.html

HTML Websocket:https://www.runoob.com/html/html5-websocket.html

  • 26
    点赞
  • 158
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值