客户端/浏览器 和 服务端在是怎么进行通信的呢 ?当前许多传统应用的 Web 项目是通过简单的 AJAX 来进行通信的,
AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
但随着当前 Web 应用对数据的实时性以及高效性,例如股票的实时行情、火车票的所剩票数、在线聊天的消息展示,随着要求的越来越高,一款应用的实时数据展示已经是其中必不可缺的一部分。
谈到 Web 实时推送,就不得不说 WebSocket。在 WebSocket 出现之前,很多网站为了实现实时推送技术,通常采用的方案是轮询( Polling )和后来出现的 Comet 技术,Comet 又可细分为两种实现方式,一种是长轮询机制,一种称为流技术,这两种方式实际上是对轮询技术的改进,这些方案带来很明显的缺点,需要由浏览器对服务器发出 HTTP request,大量消耗服务器带宽和资源。
为了实现实时数据显示,可以通过 WebServer 端之间不断的 HTTP 请求通信来获取实时数据,我们可以利用 浏览器/客户端 对服务端发送轮训(polling)去获取实时数据。但是不断的建立连接请求是要消耗我们的网络资源的,万一数据并没有出现变化,服务端也会回复重复的数据,这样也就导致了网络吞吐量的下降。那么有什么优化方法呢?
(在已知服务端数据更新的间隔情况,该方法可能是性价比比较高的)
后来推出了 LongPolling 技术,对上述 Polling 技术进行了一些改进,它与 Polling 不同的在于它在拿到请求后并不会立即发送 Response 给客户端而是将这个请求保持住,等待有新的数据到来时,再来响应这个请求;当然了,如果服务器的数据长期没有更新,一段时间后,这个Get请求就会超时。
上述 Long Polling 这种方式虽然在某种程度上减小了网络带宽和CPU利用率等问题,但是仍然存在缺陷,假设服务器端的数据更新速率较快,服务器在传送一个数据包给 Browser 后必须等待 Browser 的下一个请求到来,才能传递第二个更新的数据包给 Browser,那么这样的话,Browser显示实时数据最快的时间为2×RTT(往返时间),在网络拥塞的情况下,这是不能让用户接受的。另外,由于http数据包的头部数据量往往很大(通常有 400 多个字节),真正被服务器需要的数据却很少(有时只有10个字节左右)
推送流也是基于HTTP建立的长久连接,通信仍然是基于客户端的请求开始,不同之处在于 Response 的结果,服务器不会向客户端发送其消息已经接收完成的信号,这样连接就会保持打开的状态,并且会一直提供进一步的数据。服务端也会将资源一直推送到客户端的缓存中,这样就能实现流媒体的实时推送了。
既然推送流能够如此高效的推送服务端的数据,为什么我们不用推送流来实现实时通信呢?根据 InfoQ 上的 文章(https://www.infoq.com/articles/websocket-and-http2-coexist/)有提到,在 HTTP 2.0 推送流是否会取代 WebSocket? 答案是否定的,推送流技术能使服务器能够主动将资源发送到客户端缓存。但是,它不允许将数据向下推送到客户端应用程序本身。服务器推送仅由浏览器处理,不会弹出到应用程序代码,这意味着应用程序没有 API 来获取这些事件的通知。
通过上面的分析可知,要是在Browser能有一种新的网络协议,能支持客户端和服务器端的双向通信,且协议的头部又不那么庞大,同时也能够使客户端代理的推送 API 接口介入其中。
那么WebSocket就是肩负这样一个使命登上舞台的。
WebSocket 协议的创建标志着生活网络的真正意义上的开始,它同时也被称为网络通信历史上的第一次重大升级,就像网络本身最初所创建的那样,WebScoket 代表着将启用一种全新类型的网络产品,这款网络产品将被设计着能与网络保持永久的连接,WebSocket 就是支撑着这场革命的语言
官方对 WebSocket 的描述如下:
The WebSocket Protocol enables two-way communication between a client
running untrusted code in a controlled environment to a remote host
that has opted-in to communications from that code. The security model
used for this is the origin-based security model commonly used by web
browsers. The protocol consists of an opening handshake followed by
basic message framing, layered over TCP. The goal of this technology
is to provide a mechanism for browser-based applications that need
two-way communication with servers that does not rely on opening
multiple HTTP connections.WebSocket协议允许在受控环境中运行不受信任代码的客户端与选择从该代码进行通信的远程主机之间进行双向通信。用于此目的的安全模型是web浏览器常用的基于源代码的安全模型。该协议包括一个开始的握手,然后是基于TCP的基本消息帧。该技术的目标是为基于浏览器的应用程序提供一种机制,这些应用程序需要与不依赖于打开多个HTTP连接的服务器进行双向通信。
由上可知,要启动 WebSocket 通信,首先我们需要通过 TCP 三次握手来建立基本连接。因为 WebSocket 协议是在现在的 Web 基础设施中发布的,因此,它被设计为是向后兼容的,在一次 HTTP 通信建立之后,浏览器将向服务器发送一个升级的请求头,通知服务器需要建立 WebSocket 连接,将 HTTP 协议升级到 WebSocket ,同时将这协议的切换也作为一次握手连接。浏览器会发送如下请求头信息。
如果服务器支持 WebSocket 协议的话,它将响应回复如下请求头
在 WebSocket 连接建立之后,客户端与服务端有着类似于心跳检验机制的Ping-Pong机制,每隔一段时间客户端与服务端之间便会通过ping-pong机制确认连接的状态。
当握手完成后,WebSocket 连接处于活动状态,服务端或客户端都可以发送数据。数据包含在帧中,每一帧用 4-12 字节预固定,以确保消息可以被重建。一旦服务器和客户端统一开始一个 WebSocket 通信后,只有第一次请求是以以太网通信,之后都是通过 TCP/IP 进行通信。
传输协议介绍:
互联网都是基于两个传输层协议进行信息传输,一是 用户数据报协议(UDP),二是 传输控制协议(TCP)。两者都是用了互联网原型技术提供的网络层技术服务(IP)
TCP协议是一种可靠的传输协议,数据逐节缓冲,并根据特定的计时器传输,这种流量控制确保了数据的一致性。TCP 是面向流的,因为数据是以独立的部分进行发送的。它也有重传等机制确保消息的完整交付。
UDP协议传输是不可靠的,但是胜在速度很快,它不保证数据完整的交付,也不提供复制。它目的是能尽最大能力进行数据传输,没有流量控制,每个数据段都是被独立接收的,UDP 是一个面向消息的协议。
从 WebSocket 为何使用 TCP 上说,是为了更好的确保消息的可靠性以及低延迟,因为通信必须确保不能丢失任何包,否则传输所需要的时间可能延至两倍时长。
再至 WebSocket 所用到的 TCP 传输以及 HTTPS 握手时的 TLS 安全协议,他们所涉及到的负载大小如图 5 与图 6 所示。但图中所示有效载荷皆为 “hello world” 十三字节的数据 (104 byte)。可见在传输有效负载占比特别小的时候,无效负载会很多。
代理服务器设置在专用网络和互联网之间,他们就像一个提供内容缓存、安全性和内容过滤的中介。当 WebSocket 服务器监测到准备完成时,代理服务器会设置一个隧道来进行代理,该隧道是通过向代理服务器发出的一个 HTTP 连接语句来建立的,该语句请求代理服务器打开特定主机和端口的 TCP/IP 连接,隧道建立起来后,通信就可以不受阻碍的通过代理层进行消息传输。这也是为什么 WebSocket 不能被推送流替代的原因之一。
综上,相对于 轮询 和 Comet 技术,WebSocket 有如下优点:
WebSocket 缺点: