websocket协议简介

2023-11-11

概念介绍

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

websocket介绍

  • WebSocket协议在2008年诞生,2011年成为国际标准。
  • WebSocket是一种在单个TCP连接上进行全双工通信的协议,位于 OSI 模型的应用层。
  • WebSocket的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息。

出现背景

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

websocket与HTTP比较

http不同版本简介

相同点

  • 都是一样基于TCP的,都是可靠性传输协议。
  • 都是应用层协议。

不同点

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

联系

  • WebSocket在建立握手时,数据是通过HTTP传输的。

在这里插入图片描述

websocket握手过程

  • 1、浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
  • 2、TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。(开始前的HTTP握手)
  • 3、服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据。
  • 4、当收到了连接成功的消息后,通过TCP通道进行传输通信。

HTTP协议头

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协议版本
  • 响应头详解(web服务返回状态码101表示协议切换成功)
  • 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>

演示

  • 可以看到只需发一次request请求,后续就不需要再发request请求,可以直接进行数据的传输,并且服务端也能主动发送消息给客户端
    在这里插入图片描述
    在这里插入图片描述

抓包分析

  • 本地无法进行抓包,因此我下载了一个简易的网络库mongoose,可以把这个传到Linux服务器上,它可以实现websocket服务。
  • mongoose-master/examples/websocket-server 这个目录下就是websocket服务程序,修改main.c中的ip和端口,直接make就可以启动。同时该目录下有test.html的测试文件,我们可以拷贝到本地进行测试。
  • 客户端给服务端发送一个hello word,同时服务端也回复了一个hello word
    在这里插入图片描述
  • 可以看到,客户端发送请求时,先通过TCP建立连接,然后发送了一个HTTP的GET请求,服务端通过HTTP返回一个101,101表示的就是协议转换,告诉客户端下面要转换协议了。再往下就是通过websocket协议进行的一次数据交互。
  • 客户端GET请求详细信息。客户端通过Upgrade字段告诉服务端要使用websocket协议。
    在这里插入图片描述
  • 服务端响应详细信息。服务端返回101,表示进行协议的切换。
    在这里插入图片描述
  • 协议协商完成后,后面就是通过websocket协议进行数据传输
    在这里插入图片描述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

websocket协议简介 的相关文章

  • Websocket 连接失败并显示星号 11

    我正在尝试将 websocket 配置为与 asterisk 11 一起使用 但是存在一些问题 我遵循的步骤是 在 http conf 中启用以下内容 enabled yes bindaddr 0 0 0 0 bindport 8088 我
  • WebSockets 监听 UNIX 域套接字?

    是否可以在 nginx 服务器后面设置一个 WebSockets 服务器来处理 UNIX 域套接字上的连接 我目前在同一台计算机上有多个 WebSocket 服务器实例 并且存在端口共享问题 所有实例都必须分配一个唯一的端口 我想避免这种情
  • 使用 Netty 将 websocket 与在 tomcat 中运行的 Spring Web 应用程序集成

    我有一个使用 Netty 的 Web 套接字服务器实现 例如监听端口 8081 和一个在 Tomcat 中运行的单独的 Spring Web 应用程序 在端口 80 中运行 我想以某种方式将所有来自 localhost 80 Websock
  • 关闭旧的 php websocket

    我在用PHP Websockets https github com ghedipunk PHP Websockets创建一个简单的聊天服务器 当我第一次运行在我的服务器上创建 websocket 的 php 脚本时 一切正常 如果脚本由于
  • React Native Android 无法连接到 WebSocket

    尽管 Web 实现可以工作 但 android 模拟器以及我的设备无法连接到 WebSocket 在引发错误的地方收到以下事件错误代码 然后断开连接 connection error Event isTrusted false messag
  • WebSocket 无法与 DNS 配合使用

    我有一个网络应用程序 我正在使用 websockets 我在使用 ws myDomain com 作为 websocket 服务器的地址时遇到问题 这个问题很奇怪 因为我使用许多 PC 测试了连接 似乎这适用于大约 1 5 的 PC 当我将
  • WebSocket 和 Origin 标头字段

    以下引用自 RFC6455 WebSocket 协议 不打算处理来自任何网页的输入但 仅对于某些站点应验证 Origin 场是原点 他们期望 如果服务器不接受指示的来源 那么它应该用回复来响应 WebSocket 握手 包含 HTTP 40
  • Dispatcher-servlet 无法映射到 websocket 请求

    我正在开发一个以Spring为主要框架的Java web应用程序 特别使用Spring core Spring mvc Spring security Spring data Spring websocket 像这样在 Spring 上下文
  • 当存在打开的 ASP.NET 4.5 Websocket 时,IIS 应用程序池无法回收

    我遇到了一个问题 可以通过以下方式复制 您需要 IIS8 因此必须在 Windows 8 或 Windows Server 2012 R2 上 在 IIS 管理器中创建一个新网站 例如在端口 8881 上的 TestWs 指向一个新文件夹
  • 如何使用 POCO 发送 websocket PONG 响应

    我正在尝试使用 POCO 1 7 5 设置 websocket 服务器 POCO的样本发现here https github com pocoproject poco blob develop Net samples WebSocketSe
  • QWebSocketServer - 不释放内存

    首先 我在安全 websocket 服务器应用程序上运行 valgrind 并发现了一个问题 在 Qt Memcheck 中我必须检查 外部错误 看到它 一些字节是肯定输了 指着我的main就在我的地方QCoreApplication ex
  • Symfony 2 GeniusesOfSymfony/WebSocketBundle

    我正在 symfony 2 应用程序中工作 我需要使用 websocket 我找到了一个名为 GeniusesOfSymfony WebSocketBundle 的包 并将其集成到系统中 该捆绑包基于 JDare ClankBundle 但
  • WebSocket 的“onopen()”函数内的对象方法调用给出“函数未定义”

    我正在尝试编写一个基于 JavaScript 的 ChatClient 并希望在 onopen 或 onmessage 函数 如 this some 中调用一些其他对象方法 怎么了 var ChatClient function this
  • 使用 Webpack 代理创建 React 应用程序中的 WebSockets

    我使用版本 3 1 2 2019 年 9 月 19 日 中的 Create React App 创建了我的 React 应用程序 我试图为 Web Socket 请求配置代理 但似乎当我使用代理时 未建立连接 我用过THIS https g
  • 天文台服务器启动失败 - 无法创建套接字服务器

    我正在为自己构建一些内部工具 以使用我设置的一些模板以及可以在应用程序之间共享的一些附加功能来生成 Flutter 应用程序 目前 代码可以编译 构建并部署 但它会卡在第一个视图 空白屏幕 上 并在失败之 前重试启动 Observatory
  • 防止 NGINX 中的一个 WebSocket 连接泛滥?

    我使用这个配置来防止我的服务器上出现类似 DOS 的洪水 limit req zone binary remote addr zone one 10m rate 10r s limit req zone binary remote addr
  • IP 地址 v4/v6 等效性测试

    是否可以在使用 IPv4 和 IPv6 的双栈环境中测试 IP 地址的等效性 如果是这样 怎么办 我的应用程序使用网络套接字 https github com zaphoyd websocketpp在 Boost ASIO 之上 举个例子
  • C 代码中的握手 WebSocket

    我是 html5 及其 websocket 的新手 现在我一直在尝试用 c 制作自己的 websocket 服务器但是 这对我来说很难 我只想从 C 服务器发送 hello world 到 html 客户端 但是 我在握手方面遇到了麻烦 o
  • close 似乎不适用于 WebSocket

    我有这个简单的 JavaScript 代码 window ws new WebSocket ws 127 0 0 1 8000 ws onopen function ws send hello Ruby 中的服务器如下所示 require
  • WebSocket如何压缩消息?

    JSON stringify 显然空间利用率不高 例如 123456789 123456789 占用 20 多个字节 而它可能只需要大约 5 个字节 websocket 在发送到流之前是否会压缩其 JSON WebSocket 的核心只是一

随机推荐

  • 目标检测算法回顾之传统算法

    传统的目标检测算法 总体回顾 基于特征 基于分割 一般流程 经典算法 Harr Adaboost 流程 Harr特征 Adaboost算法 HOG SVM 概述 方法 HOG特征的优缺点 DPM DPM特征 DPM流程 DPM vs HOG
  • ER图详解及实例

    文章目录 ER图基本概念 ER图实例 ER图基本概念 ER图分为实体 属性 关系三个核心部分 在ER图中 实体是长方形 属性是椭圆形 关系为菱形 实体 entity 即数据模型中的数据对象 即数据表 用长方体来表示 每个实体都有自己的实体成
  • 超详细IDEA创建Maven项目

    文章目录 一 Maven概述 二 创建Maven项目 三 Maven项目简单介绍 3 1 标准化的项目结构 3 2 标准化的构建流程 3 3 方便的依赖管理 一 Maven概述 Maven是一个专门用于管理和构建Java项目的工具 我们之所
  • 大数据毕业设计 机器视觉图像拼接算法研究与实现 - python opencv

    文章目录 0 前言 一 拼接效果 二 算法介绍 1 拼接算法简介 1 1 基于区域相关拼接算法 1 2 基于特征相关拼接算法 1 3 拼接算法的基本流程 2 拼接算法原理 2 1 第一种 特征匹配 2 2 第二种 计算图像之间的变换结构 2
  • Topaz Video Enhance AI Mac版,视频无损放大工具

    Topaz Video Enhance AI Mac版是一款强大的视频无损放大工具 借助软件 您可以将您的素材从标清转换为高清 并获得令人难以置信的质量提升 该模具非常适合您想要用于现代用途的较旧素材
  • chatgpt赋能python:Python如何选取CSV某几列数据

    Python如何选取CSV某几列数据 在数据处理过程中 CSV是一种非常常见的数据文件类型 CSV文件中的数据由逗号分隔的值 Comma Separated Values 组成 处理CSV数据的任务之一是从CSV文件中选择特定的列数据 以进
  • 卡方检验简介

    Chi square test 卡方检验 是用于评价两类变量之间是否存在相关性的统计检验方法 医疗研究会产生大量不同类型的数据 最容易识别的是定量的数据 例如 直腿抬高 SLR 的受试者能够将腿抬高大于 0 度 这让我们可以计算两组的平均
  • IDEA常用快捷键

    一 查找类的快捷键 1 在项目中查找某个自定义类 Ctrl Shift r 2 在源码中查找某个类 Ctrl Shift n 二 大小写切换 Ctrl Shift u 三 查看类图 1 先找到那个类 一里面的快捷键 2 查看本类继承体系 C
  • 蓝宝石vega56刷64bios及降压超频全过程

    需要准备的工具有 刷bios的工具atiflash https www techpowerup com download ati atiflash 所需bios https www techpowerup com vgabios 20028
  • 批处理,%~d0 cd %~dp0 代表什么意思

    dp0 d 为Drive的缩写 即为驱动器 磁盘 p 为Path缩写 即为路径 目录 cd是转到这个目录 不过我觉得cd d dp0 还好些 选项语法 0 删除任何引号 扩充 0 f0 将 0 扩充到一个完全合格的路径名 f 是file 即
  • Java基础知识之笔记总结分享(超详细)

    给大家分享一篇我之前在学习java过程中的关于java基础部分的笔记 比较详细 内容也比较多 如有问题请指出以便修改 谢谢 篇幅较长建议收藏浏览 1 环境变量配置 JAVA HOME jdk路径 Path 要把jdk的bin目录路径 添加到
  • 深入理解 relocating 对Elasticsearch集群的影响

    rebalance 用于将集群中的分片进行均衡 保持各个节点的分片数量大致相等 当集群扩容或缩容 掉一个节点的时候 这过程会自动完成 直观的感觉他应该是在后台默默干活的过程 最多占用带宽和磁盘 io 资源 应该感受不到他的存在 但实际情况是
  • 项目经理职责与权利

    项目经理有权按工程承包合同的规定 根据项目随时出现的人 财 物等资源变化情况进行指挥调度 对于施工组织设计和网络计划 也有权在保证总目标不变的前提下进行优化和调整 一 项目经理的权力 1 生产指挥权 项目经理有权按工程承包合同的规定 根据项
  • HAProxy--理论--03--配置文件中的关键字参考

    HAProxy 理论 03 配置文件中的关键字参考 1 balance balance balance url param check post 可用于 defaults listen 和 backend 定义负载均衡算法 用于在负载均衡场
  • 圆石重磅

    Datawhale干货 分享人 武卿 刘伟博士 人工智能的飞速发展 为未来增加了诸多不确定性 未来的世界更加不可预测 ChatGPT问世以来 在全球范围内掀起了一场科技革命 人工智能的飞速发展 为未来增加了诸多不确定性 未来的世界更加不可预
  • java 数组继承_关于对象的行为、数组、继承和类的高级概念(Java)

    1 对象的行为 1 方法调用栈 所有的方法调用都维护在一个称为调用栈的结构中 第一个被调用的方法就是main 该方法是Jvm调用的 因此main 方法总是在调用栈的底部 2 调用方法 一个方法被调用时该方法就放在调用栈的顶部 直到方法执行完
  • 一张图告诉你:今年上市的独角兽,股票表现都还好吗?

    西雅图IT圈 seattleit 今日作者 栗头蓝 一个充满着人文情怀的 web前端相声演员 2019年是独角兽公司上市的大年 定义独角兽公司的一条标准是 估值超过十亿美元的创业公司 截止到6月中旬 美国共有177家这样的独角兽 相比十年前
  • SSM项目中的Layui登陆

    该登陆的的具体结构如图下 在WEB INF jsp admin目录 下创建login jsp页面 写下所需要的登陆页面html代码 在com bdqn controller admin包下创建SystemController控制器层 写页面
  • java21天打卡 day10-字符串2

    字符串2 1 截取子字符串 1 取从第三个字符开始到最后 2 取第二到第四个字符 2 分割字符串 public class Day10 public static void main String args 字符串2 1 截取子字符串 1
  • websocket协议简介

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