WebSocket协议

1. WebSocket简介

Websocket是一种网络通信协议。

Websocket是HMl5开始提供的一种在单个TCP连接上进行全双工通讯的协议。没有了 Request 和 Response 的概念,两者地位完全平等,连接一旦建立,就建立了真•持久性连接,双方可以随时向对方发送数据。使得服务器和客户端交互数据更加简单。浏览器和客户端只需要完成一次握手,就可以创建持久性的连接,并进行双向的数据传输

HTTP协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求 / 响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理

这种通信模型有一个弊端:HTTP协议无法实现服务器主动向客户端发起消息。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客戶端要获知就非常麻烦。大多数Web应用程序将通过频繁的异步AJAX请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者HTTP连接始终打开)

所以 WebSocket 和 HTTP 有一些交集,两者相异的地方还是很多。两者交集的地方在 HTTP 握手阶段,握手成功后,数据就直接从 TCP 通道传输。

轮询:在客户端定时的向服务器发送AJAX请求,获取服务端最新的数据

为什么要选择WebSocket

轮询都是先由客户端发起 Ajax 请求,才能进行通信,走的是 HTTP 协议,服务器端无法主动向客户端推送信息。

当出现类似体育赛事、聊天室、实时位置之类的场景时,轮询就显得十分低效和浪费资源。

选择WebSocket的理由:

  • 因为HTTP要不断发送请求,连接服务器,然后再等待服务器响应,时延太长,不适合实时传输,并且服务器不能主动向客户端发送请求,是单向通信的

  • 较少的控制开销。协议控制的数据包头部相对较小

  • 更强的实时双向通信性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据

  • 长连接,保持连接状态

2. WebSocket通信原理

HTTP协议:

WebSocket协议_第1张图片

延时时间长,而且只能是单向通信

101状态码

当客户端在请求里使用Upgrade报头,通知服务器它想改用除HTTP协议之外的其他协议时,客户端将获得此响应代码。101响应代码表示“行,我现在改用另一个协议了”。

通常HTTP客户端会在收到服务器发来的101响应后关闭与服务器的TCP连接。101响应代码意味着,该客户端不再是一个HTTP客户端,而将成为另一种客户端。Upgrade请求头来告知服务端客户端想要建立一个 WebSocket 连接。

在客户端建立一个 WebSocket 连接非常简单:

let ws = new WebSocket('ws://localhost:9000');

请求的 URL 是ws://或者 wss://开头的,而不是 HTTP:// 或者 HTTPS://

WebSocket协议_第2张图片

3. WebSocket协议

WebSocket协议有两部分:握手数据传输,握手是基于HTTP协议的
WebSocket协议_第3张图片

握手

客户端request请求头:

GET ws://localhostchat HTTP/1.1
Host: localhost
Upgrade: websocket  //表示要升级到websocket协议
Connection: Upgrade
Sec-WebSocket-Extensions: permessage-deflate;
Sec-WebSocket-Key: 5fTJ1LTuh3RKjSJxydyifQ==		// 与响应头 Sec-WebSocket-Accept 相对应
Sec-WebSocket-Version: 13	//表示websocket协议的版本	

服务端response响应头:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ZUip34t+bCjhkvxxwhmdEOyx9hE=
Sec-WebSocket-Extensions: permessage-deflate;

【字段说明】

头名称 说明
Connection: Upgrade 表示该HTTP请求是一个人协议升级请求
Upgrade: websocket 协议升级为WebSocket协议
Sec-WebSocket-Version: 13 表示websocket协议的版本
Sec-WebSocket-Key 与响应头 Sec-WebSocket-Accept 相对应,用来唯一标识客户端和服务器
Sec-WebSocket-Extensions 协议拓展

4. 客户端通信

WebSocket对象

​ 创建WebSocket对象:

var ws = new WebSocket(url);  //请求的地址

参数url格式:ws://ip地址:端口号/资源名称

WebSocket事件

WebSocket对象的相关事件:

事件 事件处理程序 描述
open websocket对象.onopen 连接建立时触发
message websocket对象.onmessage 客户端接收服务端数据时触发
error websocket对象.onerror 通信发生错误是触发
close websocket对象.onclose 连接关闭时触发

WebSocket方法

WebSocket对象的相关方法:

send():使用连接发送数据

5. 服务端通信

Java Websocket应用由一系列的 WebSocketEndpoint组成。 Endpoint是一个java对象,代表 WebSocket链接的一端。对于服务端,我们可以视为处理具体WebSocket消息的接口,就像Servlet之与HTTP请求一样。
我们可以通过两种方式定义 Endpoint:

  • 第一种是编程式,即继承类 javax.websocket,Endpoint并实现其方法
  • 第二种是注解式,即定义一个POJO,并添加 ServerEndpoint相关注解

Endpoint实例在 WebSocket握手时创建,并在客户端与服务端链接过程中有效,最后在链接关闭时结束。在Endpoint接口中明确定义了与其生命周期相关的方法,规范实现者确保生命周期的各个阶段调用实例的相关方法。生命周期方法如下:

方法 含义 注解
onClose 当会话开启时调用 @OoClose
onOpen 当开启一个新的会话,客户端与服务器握手成功后调用 @OnOpne
onError 连接规程中产生异常 @OnError

服务端如何接收客户端发送的数据呢?

通过为 Session添加 MessageHandler消息处理器来接收消息,当采用注解方式定义 Endpoint时,我们还可以通过@OnMessage注解指定接收消息的方法。

服务端如何推送数据绐客户端呢?

发送消息则由 RemoteEndpoint完成,其实例由 session维护,根据使用情况,我们可以通过Session.getBasicRemote获取同步消息发送的实例,然后调用其 sendXxx()方法就可以发送消息,可以通过Session.getAsyncRemote获取异步消息发送实例

心跳保活

在实际使用 WebSocket 中,长时间不通消息可能会出现一些连接不稳定的情况,这些未知情况导致的连接中断会影响客户端与服务端之前的通信,

为了防止这种的情况的出现,有一种心跳保活的方法:客户端就像心跳一样每隔固定的时间发送一次 ping,来告诉服务器,我还活着,而服务器也会返回 pong,来告诉客户端,服务器还活着。ping/pong 其实是一条与业务无关的假消息,也称为心跳包。

可以在连接成功之后,每隔一个固定时间发送心跳包,比如 60s:

setInterval(() => {
    ws.send('这是一条心跳包消息');
}, 60000)

WebSocket协议_第4张图片

通过上面的介绍,大家应该对 WebSocket 有了一定认识,其实并不神秘,这里对文章内容简单总结一下。当创建 WebSocket 实例的时候,会发一个 HTTP 请求,请求报文中有个特殊的字段 Upgrade,然后这个连接会由 HTTP 协议转换为 WebSocket 协议,这样客户端和服务端建立了全双工通信,通过 WebSocket 的 send 方法和 onmessage 事件就可以通过这条通信连接交换信息。

你可能感兴趣的:(网络)