WebSocket连接过程及原理分析

本文正在参加「金石计划」

前言

最近在面试的过程中有被问及到websocket的连接过程(简历中项目有使用到websocket),一时有点懵,以为是在问使用方式,后来确定了下是在问网络层面的连接过程,是如何进行的,以及httpsocket的过程。

我只做过心跳和断网重连的一些基本使用,对原理层面知之甚少。对于简历中的项目涉及到的websocket技术还是属于了解的比较浅的,问题很有点大啊。总的来说对于简历中的技术应该还是要做到比较熟悉才行,项目和技术栈还是有必要好好准备一番的。

为什么需要WebSocket

主要原因就是:HTTP 协议通信只能由客户端发起(HTTP是非持久的协议)

以PHP生命周期为例:

  • HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
  • 在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response

但是请记住 Request = Response, 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

对于状态监听并在变化后推送消息通知到客户端这种场景,在此之前常用的手段一般是轮询:每隔一段时候,就发出一个询问,了解服务器有没有新的信息(轮询的效率低,非常浪费资源——因为必须不停连接,或者 HTTP 连接始终打开)。

轮询这样的方法最明显的缺点就是需要不断的发送请求,而且通常HTTP request的Header是非常长的,为了传输一个很小的数据需要付出巨大的代价,是很不合算的,占用了很多的宽带资源。

简介

首先,WebSocket是HTML5新出的一种协议。

Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,有交集,但是并不是全部。

WebSocket 协议在2008年诞生,2011年成为国际标准(目前主流浏览器都支持,不存在兼容问题)。

WebSocket连接过程及原理分析

一些特点

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

WebSocket连接过程及原理分析

  1. 更强的实时性:由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。
  2. 更小的控制开销:数据格式比较轻量,性能开销小,通信高效(用于协议控制的数据包头部相对较小)。
  3. 良好的HTTP协议兼容性:与 HTTPHTTPS 使用相同的 TCP 端口,握手阶段采用 HTTP 协议,协议标识符是ws(如果加密,则为wss
  4. 更好的二进制支持:可以发送文本,也可以发送二进制数据(定义了二进制帧)。
  5. 可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。
  6. 没有同源限制,客户端可以与任意服务器通信。

WebSocket连接过程及原理分析

主要API

  • WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例(相关API见官网)。
  • 核心属性:onopenoncloseonerroronmessagebinaryTypereadyState等9个。
    • onopen:用于指定连接成功后的回调函数
    • onclose:用于指定连接关闭后的回调函数
    • onerror:用于指定连接失败后的回调函数
    • onmessage:用于指定当从服务器接收到信息时的回调函数
    • binaryType:使用二进制的数据类型连接(binaryType: "blob"
    • readyState(只读):返回当前 WebSocket 的连接状态,共有 4 种状态
  • 核心方法:sendclose
    • send:该方法将需要通过 WebSocket 链接传输至服务器的数据排入队列
    • close:该方法用于关闭 WebSocket 连接
  • 事件:opencloseerrormessage(配合addEventListener方法使用,与通过上面onopenonclose等4个属性方法设置使用一样)。
// readyState
- CONNECTING — 正在连接中,对应的值为 0;
- OPEN — 已经连接并且可以通讯,对应的值为 1;
- CLOSING — 连接正在关闭,对应的值为 2;
- CLOSED — 连接已关闭或者没有连接成功,对应的值为 3

基本用法

const ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) { 
  console.log("Connection open ..."); 
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
  console.log( "Received Message: " + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};      

webSocket与http

相同点:

  1. 都是基于TCP的可靠性传输协议。
  2. 都是应用层协议

不同点:

  1. WebSocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
  2. WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。
  3. 连接行为和状态
    • 在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输identity info(鉴别信息),来告诉服务端你是谁。
    • Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。

特殊说明:WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的

webSocket的连接过程

  1. Websocket一开始的握手需要借助HTTP请求完成,也是建立在TCP之上的,即浏览器、服务器建立TCP连接,三次握手。
  2. TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。
  3. 服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据。
  4. 当收到了连接成功的消息后,通过TCP通道进行传输通信。

在客户端,new WebSocket('ws://server.example.com')实例化一个新的WebSocket客户端对象,连接服务端WebSocket URLWebSocket客户端对象会自动解析并识别为WebSocket请求,从而连接服务端端口,执行双方握手过程。

客户端请求报文 Header

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

可以看到,客户端发起的WebSocket连接报文类似传统HTTP报文,但多出了一些东西

  • Upgrade:websocket/Connection: Upgrade:参数值表明这是WebSocket类型请求(这个是Websocket的核心,告诉Apache、Nginx等服务器,发起的是Websocket协议)。
  • Sec-WebSocket-Key:是一个Base64编码的值,是由浏览器随机生成的,提供基本的防护,防止恶意或者无意的连接。
  • Sec_WebSocket-Protocol:是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。
  • Sec-WebSocket-Version:表示 WebSocket 的版本,最初 WebSocket 协议太多,不同厂商都有自己的协议版本,不过现在已经定下来了。如果服务端不支持该版本,需要返回一个 Sec-WebSocket-Versionheader,里面包含服务端支持的版本号。

服务端响应报文 Header

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
  1. 首先,101 状态码表示服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求;
  2. 然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key
  3. 最后,Sec-WebSocket-Protocol 则是表示最终使用的协议。

注意:Sec-WebSocket-Key/Sec-WebSocket-Accept 的换算,只能带来基本的保障,但连接是否安全、数据是否安全、客户端 / 服务端是否合法的 ws 客户端、ws 服务端,其实并没有实际性的保证。

至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。

资料

原文链接:https://juejin.cn/post/7220776393373876280 作者:小帅不太帅

(0)
上一篇 2023年4月12日 上午10:48
下一篇 2023年4月12日 上午10:58

相关推荐

发表回复

登录后才能评论