初次接触Websocket的人,都会有一个问题:我们已经有了HTTP协议,为什么还需要另外一个协议?它能带来什么好处?
答案很简单,因为HTTP协议有一个缺陷:通信只能由客户端发起。HTTP协议做不到服务器主动向客户端推送信息。
Websocket协议最大的特点就是:服务器可以主动向客户端推送消息,客户端也可以主动向服务器发送消息,是真正的双向平等对话,属于服务器推送技术的一种
一.传统的实现即时通信的方式
1.Ajax轮询:Ajax轮询的原理很简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新消息。
优点:程序编写比较简单
缺点:需要服务器有很快的处理速度,请求中有大半是无用的,浪费带宽和服务器资源。
实例:适用于小型应用
2.long poll(长轮询):long poll其实原理和Ajax轮询差不多,都是采用轮询的方式,不过采用的是阻塞模型,也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
优点:在无消息的情况下不会频繁的请求,耗费资源小
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。
实例:WebQQ
3.长连接:在HTTP1.0和1.1及后面的版本都有对长连接的支持。其中HTTP1.0需要在请求头部增加”Connection:Keep-alive“才能够支持,而HTTP1.1及后面的版本默认支持。
优点:消息即时到达,不发无用请求,管理起来相对方便。
缺点:服务器维护一个长连接会增加开销。
实例:Gmail聊天
4.Flash Socket:在页面中内嵌一个使用了Socket类的Flash程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。
优点:实现真正的即时通信,而不是伪即时。
缺点:客户端必须安装Flash插件,非HTTP协议,无法自动穿越防火墙。
实例:网络互动游戏
二.Websocket的方式实现服务端消息推送
在网络中的两个应用程序(进程)需要全双工相互通信(全双工即双方可同时向对方发送消息),需要用到的就是socket,它能够提供端对端通信,对于程序员来讲,他只需要在某个应用程序的一端(暂且称之为客户端)创建一个socket实例并且提供它所要连接一端(暂且称之为服务端)的IP地址和端口,而另外一端(服务端)创建一个socket实例并绑定本地端口进行监听,然后客户端进行连接服务端,服务端接收连接后双方建立了一个端对端的TCP连接,在该连接上就可以双向通讯了,而且一旦建立这个连接之后,通信双方就没有客户端服务端之分了,提供的就是端对端通信了。从本质上来说,socket并不是一个新的协议,它只是为了便于程序员进行网络编程而对TCP/IP协议族通信机制的一种封装。
Websocket是html5规范中的一部分,它借鉴了socket这种思想,为web应用程序客户端和服务端之间提供了一种全双工通信机制。同时,它又是一种新的应用层协议,Websocket协议是为了提供web应用程序客户端和服务端全双工通信而专门制定的一种应用层协议,通常它表示为:ws://echo.websocket.org/?encoding=text HTTP/1.1,可以看到除了前面的协议名和HTTP不同之外,它的表示地址就是传统的URL地址。
Websocket其实是一种新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充。
Websocket具有以下几个方面的优势:
- 建立在TCP协议之上,服务器端实现比较容易
- 与HTTP协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用了HTTP协议,因此握手时不容易被屏蔽,能通过各种HTTP代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是ws(如果加密是wss)服务器网址就是URL。
三.Websocket的通信原理和机制
当客户端连接服务器的时候,会向服务器发送一个类似下面的报文:
这个是Websocket的核心了,告诉Apache,Nginx等服务器,发起的是Websocket协议。
首先,Sec-WebSocket-Key 是一个Base64 encode的值,这个是浏览器随机生成的。
然后,Sec-WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。
最后,Sec-WebSocket-Version 是告诉服务器所使用的Websocket Draft(协议版本)。
然后服务器会返回下列东西,表示已经接受到请求,成功建立Websocket啦。
依然是固定的,告诉客户端即将升级的是Websocket协议,而不是其他协议(mozillasocket,lurnarsocket,shitsocket)
Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。
Sec-WebSocket-Protocol 则是表示最终使用的协议。
返回的状态码为101,表示同意客户端协议转换请求,并将它转换为Websocket协议。以上过程都是利用HTTP通信完成的。称之为Websocket握手协议,经过握手后,客户端和服务器就建立了Websocket连接,以后的通信都走的是Websocket协议了。
总结就是Wobsocket协议握手需要借助于HTTP协议,建立连接后通信过程使用Websocket协议。同时需要了解的是,该Websocket连接还是基于刚才发起的HTTP连接的TCP连接。Websocket提供了两种数据传输:文本数据和二进制数据。
四.Websocket的创建和常用属性方法
以下API用于创建 Websocket 对象。
var Socket = new WebSocket(url,[protocol]);
第一个参数url指定连接的URL。第二个参数是可选的,指定了可接受的子协议。
WebSocket 属性
以下是WebSocket 对象的属性。假定我们使用以上代码创建了 Socket 对象。
WebSocket.readyState:只读属性 readyState 表示连接状态,可以是以下值:
- 0 - 表示连接尚未建立。
- 1 - 表示连接已建立,可以进行通信。
- 2 - 表示连接正在进行关闭。
- 3 - 表示连接已经关闭或者连接不能打开。
WebSocket.bufferedAmount:只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。
可以看到,当onopen触发时,对应的就是readyState的OPEN状态,不包含OPENING,onclose触发时,对应的就是CLOSED状态,不包含CLOSING状态。
WebSocket 事件
以下是WebSocket对象的相关事件。假定我们使用了以上代码创建的 Socket 对象。
WebSocket 方法
以下是WebSocket对象的相关方法。假定我们使用了以上代码创建的 Socket 对象。
用WebSocket发送接收二进制数据
WebSocket 可以通过 ArrayBuffer ,发送或接收二进制数据。
目前WebSocket的缺点是不兼容低版本的浏览器。