WebSocket

1,462 阅读9分钟

简介

  • WebSocket是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型的应用层。 WebSocket协议支持Web浏览器(或其他客户端应用程序)与Web服务器之间的交互,具有较低的开销,便于实现客户端与服务器的实时数据传输。 服务器可以通过标准化的方式来实现,而无需客户端首先请求内容,并允许消息在保持连接打开的同时来回传递。通过这种方式,可以在客户端和服务器之间进行双向持续对话。默认情况下,Websocket协议使用80端口;运行在TLS之上时,默认使用443端口。

  • WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 Websocket 必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。

  • Websocket的数据传输是frame形式传输的,比如会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:

    • 1、 大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。
    • 2 、和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。

优点

  • 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。
  • 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。
  • 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
  • 更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
  • 可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。
  • 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率

使用场景

社交聊天、弹幕、多玩家游戏、协同编辑、股票基金实时报价、体育实况更新、视频会议/聊天、基于位置的应用、在线教育、智能家居等需要高实时的场景

握手

WebSocket 是独立的、创建在 TCP 上的协议。

Websocket 通过 HTTP/1.1 协议的101状态码进行握手。

例子

客户端请求

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

服务端响应

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/
  • Connection必须设置Upgrade,表示客户端希望连接升级。
  • Upgrade字段必须设置Websocket,表示希望升级到Websocket协议。
  • Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个特殊字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算SHA-1摘要,之后进行BASE-64编码,将结果做为“Sec-WebSocket-Accept”头的值,返回给客户端。如此操作,可以尽量避免普通HTTP请求被误认为Websocket协议。
  • Sec-WebSocket-Version 表示支持的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均应当弃用。
  • Origin字段是可选的,通常用来表示在浏览器中发起此Websocket连接所在的页面,类似于Referer。但是,与Referer不同的是,Origin只包含了协议和主机名称。
  • 其他一些定义在HTTP协议中的字段,如Cookie等,也可以在Websocket中使用。

WebSocket连接的过程

在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握手的动作,然后单独建立一条TCP的通信通道进行数据的传送。

  • 首先,客户端发起http请求,经过3次握手后,建立起TCP连接;http请求里存放WebSocket支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等;
  • 然后,服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据;
  • 最后,客户端收到连接成功的消息后,开始借助于TCP传输信道进行全双工通信。

WebSocket解决了什么?

  • 1、被动性问题

    • 对于传统的请求-响应模式来说,如ajax轮询、long poll
      • ajax轮询原理: 让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
      • long poll原理:也是采用轮询的方式, 不过采取的是阻塞模型, 也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
    • 以上两种方式可以看出, 都是在不断地建立HTTP连接,然后等待服务端处理, 服务端不能主动联系客户端,只能有客户端发起。这样是非常消耗资源的。 ajax轮询 需要服务器有很快的处理速度和资源。(速度)long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
    • 对于WebSocket来说,当服务器完成协议升级后(HTTP ->Websocket),服务端就可以主动推送信息给客户端。
  • 3、资源消耗问题

    • 所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(JAVA、PHP等)来处理。Nginx等服务器处理请求的速度是足够快的,但是Handler的处理速度跟不上,导致会卡在Handler上。
    • 对于WebSocket来说,建立后,可以直接跟Nginx等服务器建立持久连接,有信息的时候Handler会想办法通知服务器,然后服务器在统一转交给客户。这样就可以解决Handler处理速度过慢的问题了。
  • 4、效率问题

    • 在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输 identity info (鉴别信息),来告诉服务端你是谁。这样就会造成效率下降, 而且还会在网路传输中消耗过多的流量/时间。
    • 对于WebSocket来说,只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。

WebSocket和HTTP比较

  • 相同点
    • 都是 基于TCP的应用层协议。
    • 都使用Request/Response模型进行连接的建立。
    • 在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码。
    • 都可以在网络中传输数据。
  • 不同点
    • WebSocket使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用。
    • WebSocket的连接不能通过中间人来转发,它必须是一个直接连接。
    • WebSocket是需要浏览器和服务器握手进行建立连接的。而HTTP是浏览器发起向服务器的连接,服务器预先并不知道这个连接。
    • WebSocket连接建立之后,通信双方都可以在任何时刻向另一方发送数据。
    • WebSocket连接建立之后,数据的传输使用帧来传递,不再需要Request消息。WebSocket的数据帧有序。而 HTTP 在“流”的层面上看,消息是一些有序的“帧”序列,而在“连接”的层面上看,消息却是乱序收发的“帧”。

WebSocket 案例分析

  • 案例介绍
    • 该客户为一个移动设备制造商,移动设备装载的是 Android/IOS 操作系统,设备分两类(以下简称 A,B 两类),A 类设备随时处于移动状态中,B 类设备为 A 类设备的管理控制设备,客户需要随时在 B 类设备中看到所属 A 类设备的地理位置信息及状态信息。如 A 类设备上线,离线的时候,B 类设备需要立即获得消息通知,A 类设备上报时,B 类设备也需要实时获得该上报 A 类设备的地理位置信息。
    • 为降低跨平台的难度及实施工作量,客户考虑轻量级的 Web App 的方式屏蔽 Android/IOS 平台的差异性,A 类设备数量众多,且在工作状态下 A 类设备处于不定时的移动状态,而 B 类设备对 A 类设备状态变化的感知实时性要求很高(秒级)。
    • 根据以上需求,A/B类设备信息存放在后台数据库中,A/B 类设备的交互涉及 Web 客户端/服务器频繁和高并发的请求-相应,如果使用传统的 HTTP 请求-响应模式,B 类设备的 Web App 上需要对服务进行轮询,势必会对服务器带来大的负载压力,且当 A 类设备没有上线或者上报等活动事件时,B 类设备的轮询严重浪费网络资源。
  • 解决方案
    • 综上所述,项目采用 WebSocket 技术实现实时消息的通知及推送,每当 A 类设备/B 类设备上线登录成功即打开 WebSocket 的 HTTP 长连接,新的 A 类设备上线,位置变化,离线等状态变化通过 WebSocket 发送实时消息,WebSocket Server 端处理 A 类设备的实时消息,并向所从属的 B 类设备实时推送。