• websocket协议


    WebSocket是一种在Web应用程序中实现实时双向通信的协议,一种在单个TCP连接上进行全双工通信的协议。它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

    WebSocket 与 HTTP/2 一样,其实都是为了解决 HTTP/1.1 的一些缺陷而诞生的,而 WebSocket 针对的就是 请求-应答 这种"半双工"的模式的通信缺陷。

    请求-应答 是"半双工"的通信模式,数据的传输必须经过一次请求应答,这个完整的通信过程,通信的同一时刻数据只能在一个方向上传递。它最大的问题在于,HTTP 是一种被动的通信模式,服务端必须等待客户端请求才可以返回数据,无法主动向客户端发送数据。

    那在 WebSocket 出现之前,一些对实时性有要求的服务,通常是基于轮询(Polling)这种简单的模式来实现。轮询就是由客户端定时发起请求,如果服务端有需要传递的数据,可以借助这个请求去响应数据。轮询的缺点也很明显,即是有大量空闲的时间,是在反复发送无效的请求,这显然是一种资源的损耗。

    就可以简单当成 HTTP1.1是单向通信的websocket是双向通信的

    想要在浏览器中实现双向通信,所以才有websocket。

    而HTTP/2是支持双向通信的,其是在websocket后才出现的。

    其如何使用c++去编写一个websocket服务器端程序,可以详细看这篇文章21.添加websocket模块

    1. WebSocket的工作流程

    WebSocket的流程可以分为三个阶段:握手、数据传输和断开连接。

    1.1 握手

    客户端发起WebSocket连接时,通过向服务器发送一个特殊的HTTP请求头来建立连接。服务器检查请求头中的特定字段,确认支持WebSocket协议后,发送特殊的HTTP响应头进行握手确认。握手成功后,双方建立了WebSocket连接,可以进行后续的数据传输。

    客户端发送的握手请求

    请求行中的请求方法必须是GET, HTTP版本至少是1.1
    请求必须含有Connection, 其值必须含有"Upgrade"记号
    请求必须含有Upgrade, 其值必须含有"websocket"关键字
    请求必须含有Sec-Websocket-Version, 其值必须是13
    请求必须含有Sec-Websocket-Key, 用于提供基本的防护, 比如无意的连接

    服务端收到客户端握手连接的回复

    响应行: HTTP/1.1 101 Switching Protocols
    响应必须含有Upgrade, 其值为"weboscket"
    响应必须含有Connection, 其值为"Upgrade"
    响应必须含有Sec-Websocket-Accept, 根据请求头部的Sec-Websocket-key计算出来。

    这个计算是有通过SHA1计算出摘要, 并转成base64字符串的。这个过程可以不用了解,我们是直接调用函数去获取结果的。

    1.2 数据传输

    一旦建立了WebSocket连接,客户端和服务器可以通过该连接进行双向的实时数据传输。双方可以发送和接收消息,消息以帧的形式进行传输。WebSocket协议定义了不同类型的帧,如文本帧和二进制帧,用于传输不同类型的数据。

    1.3 断开连接

    当连接不再需要时,客户端或服务器可以发起关闭连接的请求。双方会交换特殊的关闭帧,以协商关闭连接,并确保双方都接收到了关闭请求。

    2.websocket协议解析

    • FIN: 占1bit
      • 0表示不是消息的最后一个分片
      • 1表示是消息的最后一个分片(一般情况是用1的,表示不分包,也好处理)
    • RSV1, RSV2, RSV3: 各占1bit, 一般情况下全为0, 与Websocket拓展有关, 如果出现非零的值且没有采用WebSocket拓展, 连接出错
    • Opcode: 占4bit
      • %x0: 表示本次数据传输采用了数据分片, 当前数据帧为其中一个数据分片
      • %x1: 表示这是一个文本帧
      • %x2: 表示这是一个二进制帧
      • %x3-7: 保留的操作代码, 用于后续定义的非控制帧
      • %x8: 表示连接断开
      • %x9: 表示这是一个心跳请求(ping)
      • %xA: 表示这是一个心跳响应(pong)
      • %xB-F: 保留的操作代码, 用于后续定义的非控制帧
    • Mask: 占1bit
      • 0表示不对数据载荷进行掩码操作, 1表示对数据载荷进行掩码操作
    • Payload length: 占77+167+64bit
      • 0~125: 数据长度等于该值
      • 126: 后续的2个字节代表一个16位的无符号整数, 值为数据的长度
      • 127: 后续的8个字节代表一个64位的无符号整数, 值为数据的长度
    • Masking-key: 占0或4bytes
      • 1: 携带了4字节的Masking-key
      • 0: 没有Masking-key
    • payload data: 载荷数据

    注意的点

    1.Fin为0,表示一个完整的消息被分片成多个数据帧进行传输的,需要一直等待接到Fin为1的数据帧之后,才算收到一个完整的消息。
    2.只有客户端给服务器端发送数据时才会有masking key,服务器端给客户端发送数据不需要masking key。

    3.若payload length占用了多个字节的话,payload length需要进行转序操作(网络序<->主机序)。
     

  • 相关阅读:
    FTP服务器
    导入现有项目maven到IDE的过程记录
    MYSQL基础
    低代码平台,业务开发的“银弹”
    vue移动端项目渲染pdf步骤
    QT Creator 添加快捷生成函数、文件注释脚本
    docker技术简介
    mybatis单框架实现数据库新增、删除、修改
    【教程】在 visual studio 共享和重用项目属性
    【ROS 2 基础-常用工具】-6 Rviz基础使用
  • 原文地址:https://blog.csdn.net/m0_57408211/article/details/132781275