第一次接触到websocket是跟着b站上做项目的时候,需要实现实时聊天的功能,用websocket实现的,那么到底是如何实现的呢?
websocket最大的特点就是能主动从服务端推送消息到客户端。HTTP1.x需要keep-alive才能实现长连接,且一个request只能对应一个response。
不过实际上,websocket为了兼容各浏览器,也通过HTTP实现了挥手阶段,如下:
这是一个websocket握手:
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>
Upgrade: websocket Connection: Upgrade
表示需要升级协议,这个就是 WebSocket 的核心了,告诉 Apache 、 Nginx 等服务器:注意啦,我发起的请求要用 WebSocket 协议,快点帮我找到对应的助理处理~而不是那个老土的 HTTP。
Sec-WebSocket-Key
是客户端向服务端发送一个验证key,来验证服务端是不是真的websocket助理。
Sec-WebSocket-Protocol
是一个字符串,用来区分在同一个URL下,不同服务对应的不同协议。
Sec-WebSocket-Version
告诉服务器所使用的 WebSocket Draft (协议版本)
这之后,服务端向客户端返回下列参数,表示已经收到请求,建立了websocket连接:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat>
Sec-WebSocket-Accept
就是对客户端发送的Sec-WebSocket-Key
进行加密后返回,向客户端证明。
Sec-WebSocket-Protocol
表示最后使用的协议
以上握手成功后,websocket建连成功,就和HTTP没关系了。
在讲述websocket之前,先看看轮询和long poll
【轮询】
客户端每隔一段时间,就向服务端发送请求,询问是否有新消息
客户端 : 有消息吗?
服务端 : 没有啊。
客户端 : 现在呢?
服务端 : 没有没有。
客户端 : 有了吗?
服务端 : 没有。。。(循环)
【long poll】
客户端发起请求后,如果没消息,就一直不返回 Response 给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。
ajax轮询 需要服务器有很快的处理速度和资源。long poll 需要有很高的并发,也就是说同时接待客户的能力。
所以 ajax轮询 和 long poll 都有可能发生这种情况。
客户端:啦啦啦啦,有新信息么?
服务端:正忙,请稍后再试(503 Server Unavailable)
客户端:。。。。好吧,啦啦啦,有新信息么?
服务端:正忙,请稍后再试(503 Server Unavailable)>
【websocket】
HTTP还是无状态的,也就是,即使第一次请求成功,在请求结束,不会记住任何信息。后面即使一模一样的请求,还是要全部重新发送。
所以在这种情况下出现了 WebSocket 。他解决了 HTTP 的这几个难题。首先,被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。所以上面的情景可以做如下修改。
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request)
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:哈哈哈哈哈啊哈哈哈哈
服务端:笑死我了哈哈哈哈哈哈哈>
这样,只需要经过一次 HTTP 请求,就可以做到源源不断的信息传送了。