IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> websocket协议简介 -> 正文阅读

[网络协议]websocket协议简介

概念介绍

  • 单工通信:数据传输只允许在一个方向上传输,只能一方发送数据,另一方接收数据并发送。
  • 半双工:数据传输允许两个方向上的传输,但在同一时间内,只可以有一方发送或接收数据。
  • 全双工:同时可进行双向数据传输。

websocket介绍

  • WebSocket是一种在单个TCP连接上进行全双工通信的协议,位于 OSI 模型的应用层。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

出现背景

  • HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
  • 这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。很多网站为了实现推送技术,所用的技术都是轮询。即在特定得时间间隔,由浏览器对服务器发出http请求。

websocket与HTTP

  • websocket虽然是独立于HTTP的一种协议,但是websocket必须依赖 HTTP 协议进行一次握手(在握手阶段是一样的),握手成功后,数据就直接从 TCP通道传输,与 HTTP 无关了。

不同点

  • websocket 是持久连接,http 是短连接;
  • websocket 的协议是以 ws/wss 开头,http 对应的是 http/https;
  • websocket 是有状态的,http 是无状态的;
  • websocket 连接之后服务器和客户端可以双向发送数据,http 只能是客户端发起一次请求之后,服务器才能返回数据;
  • websocket 连接建立之后,不需要再发送request请求,数据直接从TCP通道传输。
    在这里插入图片描述

HTTP协议头

参考

请求

  • Accept: text/html,application/xhtml+xml,application/xml
  • Accept-Encoding: gzip, deflate, br
  • Accept-Language: zh-CN,zh;q=0.9
  • Connection: keep-alive
  • Host: www.baidu.com
  • User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36

响应

  • Connection: keep-alive
  • Content-Encoding: gzip
  • Content-Type: text/html;charset=utf-8
  • Date: Sat, 16 Apr 2022 10:43:46 GMT
  • Server: BWS/1.1

websocket

请求

  • Accept-Encoding: gzip, deflate
  • Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
  • Connection: Upgrade
  • Host: 192.168.1.2:8080
  • Sec-WebSocket-Key: 821VqJT7EjnceB8m7mbwWA==
  • Sec-WebSocket-Version: 13
  • Upgrade: websocket
  • User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.39

响应

  • Connection: Upgrade
  • Date: Sat, 16 Apr 2022 10:49:05 GMT
  • Sec-WebSocket-Accept: paFykwJusIMnfpohWxA5HVpjD1Q=
  • Server: Server
  • Upgrade: websocket

websocket头详解

  • 请求头详解
  • Upgrade: 向服务器指定协议类型,告诉web服务器当前使用的是websocket协议
  • Sec-WebSocket-Key:是一个 Base64 encode 的值,这个是浏览器随机生成的
  • Sec-WebSocket-Version:websocket协议版本
  • 响应头详解
  • Sec-WebSocket-Accept: 是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。用来证明客户端和服务器之间能进行通信了。

代码展示

服务端

服务端程序是通过QT实现

  • websocketservice.h
#ifndef WEBSOCKETSERVER_H
#define WEBSOCKETSERVER_H

#include <QWidget>
#include <QWebSocketServer>
#include <QWebSocket>
#include <QHostInfo>
#include <QNetworkInterface>

namespace Ui {
class WebSocketServer;
}

class WebSocketServer : public QWidget
{
    Q_OBJECT

public:
    explicit WebSocketServer(QWidget *parent = 0);
    ~WebSocketServer();

private slots:
    void on_pushButton_startListen_clicked();
    void onNewConnection();
    void onTextMessageReceived(QString msg);
    void onDisconnected();


    void on_pushButton_send_clicked();

private:
    Ui::WebSocketServer *ui;
    QWebSocketServer *server;
    QWebSocket *socket;
    QList<QWebSocket*> clientList;

    QString mAddr;
    int mPort;
};

#endif // WEBSOCKETSERVER_H
  • websocketservice.cpp
#include "websocketserver.h"
#include "ui_websocketserver.h"

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


    //获取本机IP和端口
    QString hostName = QHostInfo::localHostName();   //获取主机名
    QHostInfo hostInfo = QHostInfo::fromName(hostName); //获取主机信息
    QList<QHostAddress> addList = hostInfo.addresses(); //获取IP地址列表

    QString localIP;
    if(!addList.isEmpty())
    {
        for(int i = 0; i < addList.count();i++)
        {
            QHostAddress aHost = addList.at(i);
            if(QAbstractSocket::IPv4Protocol == aHost.protocol())
            {
                localIP = aHost.toString();
                break;
            }
        }
    }

    ui->lineEdit_url->setText(localIP);
    ui->lineEdit_port->setText("8080");


    //构造: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);

    //有新的连接
    connect(server,&QWebSocketServer::newConnection,this,&WebSocketServer::onNewConnection);

}

WebSocketServer::~WebSocketServer()
{
    delete ui;
}

void WebSocketServer::on_pushButton_startListen_clicked()
{
    QHostAddress address = QHostAddress(ui->lineEdit_url->text());
    if(server->listen(address, ui->lineEdit_port->text().toInt())){
        ui->pushButton_startListen->setEnabled(false);
        ui->pushButton_startListen->setText("disListen");
    }
}

void WebSocketServer::onNewConnection()
{
    socket=server->nextPendingConnection();
    mAddr = socket->peerAddress().toString();
    mPort = socket->peerPort();

    ui->plainTextEdit_clientStatus->appendPlainText("[" + mAddr + ":" + QString::number(mPort) + "]" + " connected...");

    ui->pushButton_send->setEnabled(true);

    connect(socket,&QWebSocket::textMessageReceived, this, &WebSocketServer::onTextMessageReceived);

    ui->plainTextEdit_sendMsg->clear();
    ui->plainTextEdit_sendMsg->appendPlainText("welcome to connect Server!");

    //断开连接时
    connect(socket,&QWebSocket::disconnected, this, &WebSocketServer::onDisconnected);
}

void WebSocketServer::onTextMessageReceived(QString msg)
{
    ui->plainTextEdit_recvMsg->appendPlainText(msg);
}

void WebSocketServer::onDisconnected()
{
    ui->plainTextEdit_clientStatus->appendPlainText("[" + mAddr + ":" + QString::number(mPort) + "]" + " disConnected!");
}

void WebSocketServer::on_pushButton_send_clicked()
{
    socket->sendTextMessage(ui->plainTextEdit_sendMsg->toPlainText());
}

客户端

<!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://192.168.1.2:8080" />
    <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, I am websocket Client!</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
				console.log("no 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>
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 18:20:11  更:2022-04-18 18:21:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:21:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码