http协议是一种单向的网络协议。其特点是只能有客户端向服务端主动发起请求,服务端被动响应。在实际场景中,很多应用比如监控、即时通信、即时报价等都需要将服务端发生的变化实时推送给客户端。传统的http协议要实现这种效果,只能通过客户端不断地刷新、发送请求实现,效率不高。
Web中实现实时通信,目前主要有如下几种方式:
1、轮询(polling)这种方式通过客户端按一定的频率间隔向服务端发送查询请求实现。比如,在js中通过setTimeout设置定时器,以一定的频率间隔发送ajax请求到服务端获取最新的数据。如下图所示:
轮询通过周期查询实现实时推送的效果。缺点也很明显:存在空载查询,浪费带宽,消耗服务器资源。间隔时间短,空载查询就多。间隔时间长,达不到实时推送的效果。
2、长轮询(comet)这种方式是对轮询方式的一种改进。原理是客户端发起查询请求后,服务端会阻塞这个请求直到有数据返回或者连接超时。当客户端收到响应后,再发起一个查询请求等待服务端响应。如下图所示:
长轮询通过阻塞请求,解决了空载查询的问题。但是,由于轮询、长轮询都是利用http协议,每次请求都会携带http包头信息。通常http包头比推送的数据要大的多。还是存在带宽浪费的问题。
3、websocketwebsocket是HTML5制定的一种新的协议。它实现了客户端与服务器全双工通信(full-duplex)。完全解决了上面两张方式中存在的问题。是web实时通信的首选方案。
二、websocket简介
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。目的是取代轮询和 Comet 技术,使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力。
客户端通过 JavaScript 向服务端发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务端就可以通过 TCP 连接直接交换数据。
Websocket具有数据传输稳定、数据传输量小等特点。客户端与服务端之间的数据包文件头大概只有2个字节。轮询与websocket的性能比较如下图所示:
三、websocket协议
1、websocket与TCP、HTTP的关系
websocket协议本质上是基于TCP协议。其url前缀是ws://和wss://。它与TCP、HTTP协议的关系如下:
websocket协议的实现需要借助于HTTP协议。 因为握手阶段需要使用HTTP协议,所以也有人理解为"HTTP握手+TCP数据传输"的协议。
2、websocket协议握手过程Websocket协议握手过程如下所示:
2.1、客户端与服务端通过TCP三次握手建立连接。
2.2、在TCP建立连接成功后,客户端通过HTTP协议传送websocket协议相关信息给服务器端。
2.3、服务端收到客户端发送来的握手请求后,如果包数据和格式正确,就接收本次握手连接,并给出相应的数据回复。
握手请求和响应包如下所示:
websocket的数据传输是以frames形式传输的,比如会将一条消息分为几个frames,按照先后顺序传输出去。数据帧格式如下所示:
字段说明:
FIN:1bit,用来表示这是一个消息的最后一帧,当然第一个消息片段也可能是最后一帧。
RSV1、RSV2、RSV3:分别1bit,如果双方之间没有约定的自定义协议,那么这几位必须为0。
Opcode:4bit,用于描述消息类型,消息类型暂定15种。
* %x0 表示连续消息片断
* %x1 表示文本消息片断
* %x2 表未二进制消息片断
* %x3-7 为将来的非控制消息片断保留的操作码
* %x8 表示连接关闭
* %x9 表示心跳检查的ping
* %xA 表示心跳检查的pong
* %xB-F 为将来的控制消息片断的保留操作码
Mask:1bit,定义传输的数据是否有加掩码。
Payloadlen:传输的数据长度,以bits的形式表示:7bits、7+16bits、7+64bits。如果数据长度在0-125bytes内,那么只要7bit就可以表示数据长度。如果数据长度大125小于UINT16 bytes,那么前7bit值为126,后面2bytes表示真实的数据长度。如果数据长度大于UINT16 bytes小于UINT64 bytes,那么前7bit值为127,后面的4bytes表示真实的数据长度。
Masking-key:0bit或4bytes,如果Mask为0,没有该值。如果Mask为1,为一个32bit的掩码。
Payload Data:(x+y)bit,负载数据为扩展数据和应用数据长度之和。
Extension Data:x位,如果客户端与服务端没有特殊约定,那么扩展数据位为0。
Application Data:y位,应用数据,放在扩展数据后。
4、浏览器支持
目前各种语言都有websocket实现库或框架。这里只列出基于node的websocket框架:
socket.io
einaros/ws
engine.io
primus