WebSocket入门
一、相关知识铺垫
1.1 OSI 7层模型
互联网的实现分成好几层,每一层都有自己的功能,就像建筑物一样,每一层都靠下一层支持。
OSI模型就是这样的一个分层,它是一个由国际标准化组织提出的概念模型,试图提供一个使各种不同的计算机和网络在世界范围内实现互联的标准框架。
OSI模型:
应用层,定义了用于在网络中进行通信和传输数据的接口;(Http协议位于该层)
表示层,定义不同系统中数据的传输格式,编码和解码规范等;
会话层,管理用户的会话,控制用户间逻辑连接的建立和中断;
传输层,管理着网络中端到端的数据传输;(Tcp协议位于该层)
网络层,定义网络设备间如何传输数据;(IP位于该层)
链路层,将上面的网络层的数据包封装成数据帧,便于物理层传输;
物理层,这一层主要就是传输这些二进制数据。
TCP/IP四层模型:
TCP/IP和OSI模型组并不能精确的匹配,但是我们可以尽可能的参考OSI模型并在其中找到TCP/IP的对应位置。
如上图所示,通常人们认为OSI模型最上面三层(应用层、表示层、会话层)在TCP/IP中是一个应用层。
应用层,提供用户和应用程序之间的接口;
传输层,负责数据在网络中传输时的可靠性、流量控制和校正;
网络层,控制流量的流动和路由、寻址,确保数据快速准确地发送,还负责在其目的地重新组装数据包;
网络接口层,涉及计算机连接互联网的基础设施,负责同一网络上两个设备之间的数据传输,将IP数据报封装成网络传输的帧;
两者区别:
OSI是一个完整的、完善的宏观模型,他包括了硬件层(物理层),当然也包含了很多上面图中没有列出的协议(比如DNS解析协议等);
而 TCP/IP 模型,更加侧重的是互联网通信核心(也是就是围绕TCP/IP协议展开的一系列通信协议)的分层,因此它不包括物理层,以及其他一些不相干的协议;
其次,之所以说他是参考模型,是因为他本身也是OSI模型中的一部分,因此参考OSI模型对其分层。
1.2 TCP
TCP/IP协议是全球计算机及网络设备都在使用的一种常用的分组交换网络分层协议集,是互联网标准通信的基础。
它提供点对点的链接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。
主要特点如下:
-
面向连接的传输层协议:在使用TCP协议之前,应用程序必须先建立TCP连接。在传输数据完毕后,必须释放已经建立的TCP连接。这种连接方式类似于打电话,通话前需要建立连接,通话结束后需要释放连接。
-
点对点通信:每一条TCP连接只能有两个端点,实现的是点对点的通信。
-
提供可靠的数据传输服务:TCP通过序号确认、超时重传和数据包重新排序等机制确保数据的可靠传输。
-
全双工通信:TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。
-
面向字节流:TCP中的“流”指的是流入到进程或从进程流出的字节序列。虽然应用程序和TCP的交互是一次一个数据块,但TCP把应用程序交下来的数据看成是一连串的无结构的字节流。
建立起一个TCP连接需要经过“三次握手”:
- 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求。
1.3 HTTP协议
基础概念:
HTTP(Hyper Text Transformer Protocol,超文本传输协议)是一种通信协议,是建立在TCP协议之上的一种应用协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”。
要保持客户端程序的在线状态,需要不断地向服务器发起连接请求,通常情况下即使不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,
服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
问题1:短连接
通常一个网页可能会有很多组成部分,除了文本内容,还会有诸如:js、css、图片等静态资源,有时还会异步发起AJAX请求。只有所有的资源都加载完毕后,我们看到网页完整的内容。
然而,一个网页中,可能引入了几十个js、css文件,上百张图片,如果每请求一个资源,就创建一个连接,然后关闭,代价实在太大了。
基于此背景,我们希望连接能够在短时间内得到复用,在加载同一个网页中的内容时,尽量的复用连接,这就是HTTP协议中keep-alive属性的作用。
如图,可以看到请求 header 中有一行 Connection : keep-alive
我们知道 HTTP 协议采用 请求-应答 模式,当使用普通模式,即非 Keep-Alive 模式时,对于每个请求客户和服务器都要新建一个连接,完成之后立即断开连接;
当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep- Alive 功能避免了建立或者重新建立连接。
- http 1.0 中默认是关闭的,需要在 http 头加入
Connection: Keep-Alive
,才能启用 Keep-Alive;
- http 1.1 中默认启用 Keep-Alive,如果加入
Connection: close
,才关闭。
keep-alive 是通知服务器,在这个 HTTP Request/Responset 结束后,不要立即断开 TCP 连接,后面的HTTP Request仍然可以通过这个TCP连接继续传送。
这只是个建议,服务器可能不支持,也可能忽略掉这个建议。也可能因为时间太久而直接断开TCP连接,所以,keep-alive只是客户端建议的一种复用TCP连接的方式,至于服务器支持不支持,就由不得客户端了。
目前大部分浏览器都是用 http 1.1 协议,也就是说默认都会发起 Keep-Alive 的连接请求了,所以是否能完成一个完整的 Keep- Alive 连接就看服务器设置情况。
Nginx 中设置 Keep-Alive(服务端)
Tomcat 中设置 Keep-Alive(服务端)
问题2:请求-响应模型
服务器端要想主动的push消息给客户端,这是不可能的,但我可以使用ajax轮询、long poll 技术造一个服务端给客户端主动push消息的假象。
- ajax轮询:原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。但这样会大大增加了服务端的负载,并且存在延迟;
- long poll:客户端发起一个请求连接,这个连接会阻塞住,直到服务端有了消息,才会response给客户端,既想阻塞,又想高并发,几乎不可能;
二. HTTP 与 WebSocket:
上文中说到HTTP1.1已经支持了长连接,为什么还要引入WebSocket作为补充呢。
WebSocket 是 HTML5 一种新的协议,它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据。
TCP是全双工的,但HTTP 1.1在TCP基础上实现的是半双工通信,又因为HTTP是请求-响应模型,这使得服务端不具备主动推送数据资源给客户端的能力。
- 单工:指消息只能单方向传输的工作方式,发送端和接收端的身份是固定的,发送端只能发送信息,不能接收信息;接收端只能接收信息,不能发送信息,数据信号仅从一端传送到另一端;(遥控器)
- 半双工:指数据可以沿两个方向传送,但同一时刻一个信道只允许单方向传送,因此又被称为双向交替通信;(对讲机)
- 全双工:指在通信的任意时刻,线路上可以同时存在A到B和B到A的双向信号传输;(电话)
基于请求-响应模型如果我们需要服务端的消息数据,就必须先向服务端发送对应的查询请求,因此对于实时的数据交互业务,需要客户端定时向服务器发起查询请求,这样的做法实在不够优雅。