Qt WebSocket

简介

WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。允许服务端主动向客户端推送数据

在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。WebSocket协议基于TCP协议实现,包含初始的握手过程,以及后续的多次数据帧双向传输过程。

默认情况下:WebSocket 协议使用 80 端口;

WebSocket目前支持两种统一资源标志符ws和wss,类似于HTTP和HTTPS。

如:  ws://example.com:80/some/path

如:  ws://127.0.0.1:45678    即ip+端口

产生背景:

因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开), 因此websocket应运而生。

优点:

1)较少的控制开销:在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小;

2)更强的实时性:由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少;

3)保持连接状态:与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息;

4)更好的二进制支持:WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容;

5)可以支持扩展:WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。

QWebSocket

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

QT += websockets

QWebSocket
常用函数

QHostAddress localAddress() const;

quint16 localPort() const;

QUrl requestUrl() const;

QNetworkRequest request() const;

当有需要接收的数据时,会发出该信号

void textMessageReceived(const QString &message);  //字符串的方式接收数据信息

void binaryMessageReceived(const QByteArray &message);//二进制的方式接收数据信息

当需要发送数据时,调用下面的发送函数

qint64 sendTextMessage(const QString &message); //字符串的方式发送数据信息

qint64 sendBinaryMessage(const QByteArray &data);//二进制的方式发送数据信息

客户端断开连接,收到断开信号:

void disconnected();

服务端QWebSocketServer

QWebSocketServer以 QTcpServer 为模型,并且行为相同。所以,如果你知道如何使用 QTcpServer,你就知道如何使用 QWebSocketServer.

常用的函数、信号、槽函数:
  1. bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);

监听连接。 如果端口为 0,则自动选择一个端口。 如果地址是 QHostAddress::Any,则服务器将侦听所有网络接口。

  1. void newConnection();  信号,接收连接,发出该信号
  2. virtual QWebSocket *nextPendingConnection();  //获取连接的客户端
  3. void close();    //关闭监听套接字

流程
  1. 创建服务器:new QWebSocketServer
  2. 监听:listen

m_pWebSocketServer->listen(QHostAddress::LocalHost, mPort);//端口号

  1. 有新的连接,触发这个信号:QWebSocketServer::newConnection
  2. 在处理newConnection信号的槽函数中,获得新的QWebSocket客户端:QWebSocketServer::nextPendingConnection
  3. 接收到信息时候,触发信号:QWebSocket::binaryMessageReceived或者QWebSocket::textMessageReceived
  4. 发送数据,调用函数QWebSocket::sendTextMessage或QWebSocket::sendBinaryMessage
  5. 客户端断开连接,触发信号:QWebSocket::disconnected,在处理disconnected信号的槽函数中,QWebSocket客户端调用deleteLater,进行释放资源。
  6. 主动关闭服务端,调用QWebSocketServer::close,所有的客户端连接qDeleteAll(m_clients.begin(), m_clients.end());

客户端QWebSocket

客户端直接使用QWebSocket的函数进行操作即可

流程
  1. 创建客户端:new QWebSocket
  2. 通过QWebSocket的open 函数连接服务端的 Url
  3. 连接服务端成功后,会触发QWebSocket::connected信号。从而获知连接成功
  4. 发送数据,调用函数QWebSocket::sendTextMessage或QWebSocket::sendBinaryMessage
  5. 接收到信息时候,触发信号:QWebSocket::binaryMessageReceived或者QWebSocket::textMessageReceived
  6. 客户端关闭时,要主动调QWebSocket的close函数,让服务端知道该客户端已断开连接。
  7. 断开连接成功,会触发信号QWebSocket::disconnected,在该信号的槽函数处理断开连接的相应工作。

完整代码

开发环境:QT5.15.2 MSVC 2019 64Bit

服务端
#ifndef WIDGET_H

#define WIDGET_H



#include 

#include 

#include 

#include 



QT_BEGIN_NAMESPACE

namespace Ui { class Widget; }

QT_END_NAMESPACE



class Widget : public QWidget

{

    Q_OBJECT



public:

    Widget(QWidget *parent = nullptr);

    ~Widget();





signals:

    void sendTextMessageSignal(QString msg);

private slots:

    void on_pushButton_Listen_clicked();



    void OnNewConnectionSlot();



    void OnTextReceivedSlot(QString msg);



    void OndisconnectedSlot();



    void on_pushButton_send_clicked();



private:

    Ui::Widget *ui;



    QWebSocketServer *server;



    QList m_clientList;



    QMap m_clientStatus;



};

#endif // WIDGET_H





#include "widget.h"

#include "ui_widget.h"



Widget::Widget(QWidget *parent)

    : QWidget(parent)

    , ui(new Ui::Widget)

{

    ui->setupUi(this);



    server = new QWebSocketServer("testserver",QWebSocketServer::NonSecureMode,this);



    connect(server,&QWebSocketServer::newConnection,this,&Widget::OnNewConnectionSlot);



    ui->lineEdit_address->setText("Any");

    ui->lineEdit_port->setText("45678");

}



Widget::~Widget()

{

    qDeleteAll(m_clientList);

    server->close();

    delete ui;

}



void Widget::on_pushButton_Listen_clicked()

{

    QHostAddress address;

    if(ui->lineEdit_address->text()=="Any")

    {

        address=QHostAddress::Any;

    }

    else

    {

        address=QHostAddress(ui->lineEdit_address->text());

    }

    int nPort = ui->lineEdit_port->text().toInt();

    bool bListen = server->listen(address,nPort);

    if(bListen)

        ui->pushButton_Listen->setEnabled(false);

}



void Widget::OnNewConnectionSlot()

{

    QWebSocket *client = server->nextPendingConnection();

    m_clientList.append(client);

    qDebug() << "Client:" << client->peerAddress().toString() << client->peerName() <peerPort() ;

    QString strstatus = "ip:" + client->peerAddress().toString() + " 端口:"+  QString::number(client->peerPort()) + "连接成功\n";

    m_clientStatus.insert(client,strstatus);

    ui->textEdit_clientlist->insertPlainText(strstatus);

    ui->textEdit_clientlist->



    connect(client,&QWebSocket::textMessageReceived,this,&Widget::OnTextReceivedSlot);

    connect(this,&Widget::sendTextMessageSignal,client,&QWebSocket::sendTextMessage);//给所有客户端发送数据

    connect(client,&QWebSocket::disconnected,this,&Widget::OndisconnectedSlot);



}



void Widget::OnTextReceivedSlot(QString msg)

{

    ui->textEdit_recv->setText(msg);

    QWebSocket *pClient = qobject_cast(sender());

    pClient->sendTextMessage("回答" + msg);

}



void Widget::OndisconnectedSlot()

{

    QWebSocket *pClient = qobject_cast(sender());

    m_clientStatus.remove(pClient);

    ui->textEdit_clientlist->clear();

    QList textlist = m_clientStatus.values();

    for(auto text : textlist)

    {

        ui->textEdit_clientlist->insertPlainText(text);

    }

    m_clientList.removeAll(pClient);

    pClient->deleteLater();

}



void Widget::on_pushButton_send_clicked()

{

   QString msg = ui->textEdit_send->toPlainText();

    emit sendTextMessageSignal(msg);

}

客户端
#ifndef WIDGET_H

#define WIDGET_H



#include 

#include 



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_pushButton_connect_clicked();



    void onConnectedSlot();



    void ondisconnectedSlot();



    void onTextReceivedSlot(QString message);



    void on_pushButton_send_clicked();



    void on_pushButton_disconnect_clicked();



private:

    Ui::Widget *ui;



     QWebSocket *m_ClientSocket;

};

#endif // WIDGET_H





#include "widget.h"

#include "ui_widget.h"



Widget::Widget(QWidget *parent)

    : QWidget(parent)

    , ui(new Ui::Widget)

{

    ui->setupUi(this);

    m_ClientSocket = new QWebSocket();

    m_ClientSocket->setParent(this);

    ui->label_connet->setText("尚未连接服务端");

    ui->pushButton_connect->setEnabled(true);

    ui->pushButton_disconnect->setEnabled(false);

    ui->lineEdit_url->setText("ws://127.0.0.1:45678");

}



Widget::~Widget()

{

    m_ClientSocket->close();

    delete ui;

}



void Widget::on_pushButton_connect_clicked()

{

    QUrl url(ui->lineEdit_url->text());

    m_ClientSocket->open(url);

    connect(m_ClientSocket, &QWebSocket::connected, this, &Widget::onConnectedSlot);

    connect(m_ClientSocket, &QWebSocket::disconnected, this, &Widget::ondisconnectedSlot);

}



void Widget::onConnectedSlot()

{

    ui->pushButton_connect->setEnabled(false);

    ui->pushButton_disconnect->setEnabled(true);

    QString strstatus =  "连接服务端" +  ui->lineEdit_url->text() + "成功";

    ui->label_connet->setText(strstatus);

    connect(m_ClientSocket, &QWebSocket::textMessageReceived, this, &Widget::onTextReceivedSlot);

}



void Widget::ondisconnectedSlot()

{

    QString strstatus =  "断开服务端" +  ui->lineEdit_url->text() + "连接";

    ui->label_connet->setText(strstatus);

    ui->pushButton_connect->setEnabled(true);

    ui->pushButton_disconnect->setEnabled(false);

}



void Widget::onTextReceivedSlot(QString message)

{

    ui->textEdit_recv->setText(message);

}



void Widget::on_pushButton_send_clicked()

{

    QString message = ui->textEdit_send->toPlainText();

    m_ClientSocket->sendTextMessage(message);

}



void Widget::on_pushButton_disconnect_clicked()

{

    m_ClientSocket->close();

}

你可能感兴趣的:(qt,qt,websocket,开发语言)