写点什么

小学生都能读懂的网络协议之:WebSocket

发布于: 18 小时前

简介

服务端和客户端应该怎么进行通信呢?我们常见的方法就是客户端向服务器端发送一个请求,然后服务器端向客户端发送返回的响应。这种做法比较简单,逻辑也很清晰,但是在某些情况下,这种操作方式并不好使。

比如在服务器端的某些变动需要通知客户端的情况,因为客户端并不知道服务器端的变动是否完成,所以需要不停的使用轮循去检测服务器的状态。这种做法的缺点就是太过于浪费资源。如果希望及时性好的话,需要不断的减少轮循的时间间隔,导致极大的服务器压力和资源的浪费。

那么有没有好的解决办法呢?

既然不能使用查询,那么就改成服务器推送就行了。我们知道在 HTTP/2 中,提供了一种服务器推送的方式,但是这种方式是单向的,也就是说在同一个 TCP 连接之上,并不能实现客户端和服务器端的交互。

于是我们需要一个能够双向交互的网络协议,这个协议就是 WebSocket。

webSocket vs HTTP

webSocket 是一个基于底层 TCP 协议的一个双向通信网络协议。这个双向通信是通过一个 TCP 连接来实现的。webSocket 于 2011 年以 RFC 6455 发布成为 IETF 的标准。

同样作为基于 TCP 协议的标准协议,它和 HTTP 有什么区别呢?

如果以 OSI 的七层模型来说,两者都位于七层协议的第四层。但是两者是两种不同的协议。鉴于 HTTP 已经如此流行了,为了保证 webSocket 的通用性,webSocket 也对 HTTP 协议进行了兼容。也就是说能够使用 HTTP 协议的地方也就可以使用 webScoket。

这个和之前讨论的 HTTP3 有点类似,虽然 HTTP3 是一个新的协议,但是为了保证其广泛的应用基础,HTTP3 还是在现有的 UDP 协议上进行重写和构建。目的就是为了兼容。

实时上,webSocket 使用的是 HTTP upgrade header,从 HTTP 协议升级成为 webSocket 协议。

HTTP upgrade header

什么是 HTTP upgrade header 呢?

HTTP upgrade header 是在 HTTP1.1 中引入的一个 HTTP 头。当客户端觉得需要升级 HTTP 协议的时候,会向服务器端发送一个升级请求,服务器端会做出相应的响应。

对于 websocket 来说,客户端在和服务器端建立连接之后,会首先发送给服务器端 Upgrade: WebSocket 和 Connection: Upgrade 头。服务器端接收到客户端的请求之后,如果支持 webSocket 协议,那么会返回同样的 Upgrade: WebSocket 和 Connection: Upgrade 头到客户端。客户端接收到服务器端的响应之后,就知道服务器端支持 websocket 协议了,然后就可以使用 WebSocket 协议发送消息了。

websocket 的优点

其实前面我们也讲过了,相对于传统的 HTTP 拉取,webSocket 可以借助于一个 TCP 连接实现数据的实时传输。可以在减少服务器压力的同时,实现服务器和客户端的实时通信。

webScoket 的应用

WebSocket 使用的是 ws 和 wss 作为 URI 的标记符。其中 ws 表示的是 websocket,而 wss 表示的是 WebSocket Secure。

因为通常来说我们使用的 web 浏览器来和服务器进行通信。浏览器就是我们的 web 客户端,对于现代浏览器来说,基本上都支持 WebSocket 协议,所以大家可以放心应用,不用担心协议兼容的问题。

对于浏览器客户端来说,可以使用标准的浏览器 WebSocket 对象,来和服务器进行通信,我们看一个简单的 javascript 客户端使用 webSocket 进行通信的例子:

// 使用标准的WebSocket API创建一个socket连接const socket = new WebSocket('ws://www.flydean.com:8000/webscoket');
// 监听webSocket的open事件socket.onopen = function () { setInterval(function() { if (socket.bufferedAmount == 0) socket.send(getUpdateData()); }, 50);};
// 监听接收消息事件socket.onmessage = function(event) { handleUpdateData(event.data);};
// 监听socket关闭事件socket.onclose = function(event) { onSocketClose(event);};
// 监听error事件socket.onerror = function(event) { onSocketError(event);};
复制代码

上述代码主要就是各种监听 socket 的事件,然后进行处理,非常简单。

websocket 的握手流程

上面我们讲过了,websocket 是从 HTTP 协议升级的,客户端通过发送:

Upgrade: websocketConnection: Upgrade

复制代码

到服务器端,对协议进行升级。我们举一个具体的例子:

GET /webscoket HTTP/1.1Host: www.flydean.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x123455688xafe=Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://flydean.com
复制代码

对应的 server 端的返回:

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: Qhfsfew12445m=Sec-WebSocket-Protocol: chat
复制代码

在上面的例子中,除了使用 Upgrade 头之外,客户端还向服务器端发送了 Sec-WebSocket-Key header。这个 header 包含的是一个 base64 编码的随机字节。server 对应的会返回这个 key 的 hash 值,并将其设置在 Sec-WebSocket-Accept header 中。

这里并不是为了安全操作,而是为了避免上一次的连接缓存情况。

WebSocket API

要想在浏览器端使用 WebSocket,那么就需要用到客户端 API,而客户端 API 中最主要的就是 WebSocket。

它提供了对 websocket 的功能封装。它的构造函数是这样的:

WebSocket(url[, protocols])
复制代码

url 就是要连接的 websocket 的地址,那么可选的 protocols 是什么呢?protocols 可以传入单个协议字符串或者是协议字符串数组。它指的是 WebSocket 服务器实现的子协议。

子协议是在 WebSocket 协议基础上发展出来的协议,主要用于具体的场景的处理,它是是在 WebSocket 协议之上,建立的更加严格的规范。

比如,客户端请求服务器时候,会将对应的协议放在 Sec-WebSocket-Protocol 头中:

GET /socket HTTP/1.1...Sec-WebSocket-Protocol: soap, wamp
复制代码

服务器端会根据支持的类型,做对应的返回,如:

Sec-WebSocket-Protocol: soap
复制代码

WebSocket API 有四种状态,分别是:

通过调用 close 或者 Send 方法,会触发相应的 events 事件,WebSocket API 的事件主要有:close,error,message,open 这 4 种。

下面是一个具体使用的例子:

// 创建连接const socket = new WebSocket('ws://localhost:8000');
// 开启连接socket.addEventListener('open', function (event) { socket.send('没错,开启了!');});
// 监听消息socket.addEventListener('message', function (event) { console.log('监听到服务器的消息 ', event.data);});
复制代码

总结

以上就是 websocket 的简单介绍和使用,有想知道 Websocket 到底是怎么进行消息传输的,敬请期待我的下一篇文章。

本文已收录于 http://www.flydean.com/06-websocket/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 18 小时前阅读数: 5
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
小学生都能读懂的网络协议之:WebSocket