一:为什么WebSocket
在传统的互联网通信上,我们一般都是用http协议,客户端向服务器发起请求,服务器作出响应,返回静态资源或对数据库做读写操作等。但这种情况下,服务器是一个被动的角色,不能主动向客户端推送消息。想要达到“推送”的效果,一般只能采用轮询的方式,由客户端按一定时间间隔发起请求,如果数据有更新,则服务器返回新数据,客户端处理新数据并重新渲染。
http虽然简单,但它基于“request--response”这种半双工方式,如果每次传递的数据很小,轮询的开销就显得大了。所以人们试图寻找一种更好的实现服务器端向客户端推送数据的方式。
这时候HTML5定义了WebSocket协议。
WebSocket是一个独立的创建在TCP上的协议,它使用ws或wss的统一资源标志符。使用和HTTP相同的端口号。ws---80,wss--443,通过HTTP/1.1的101状态码进行握手。
它可以发送文本或二进制数据。没有同源限制。
创建websokect链接时,需要客户端先发起请求,然后服务器回应,这个过程称“握手”。
ws://example.com/wsapi wss://secure.example.com/
二:WebSokect在前端的操作:
我记得刚接触前端的时候,以为ajax是很复杂的东西。但接触后发现,前端的ajax不过是操作XMLHttpRequest对象。我们new了一个XMLHttpRequest对象后,调用它的open()、onreadystatechange()、setRequestHeader()、send()等方法,就能向指定的服务器发起GET/POST请求并设定回调,而其API底层已经帮我们封装了对http操作。
WebSocket也是一样的,我们可以在js中通过new一个WebSocket对象,传入绝对URL,并调用其api来实现基于ws协议的双向连接。
1 var ws = new WebSocket("wss://echo.websocket.org"); 2 //创建连接成功,可以准备通讯 3 ws.onopen = function(evt) { 4 console.log("Connection open ..."); 5 ws.send("Hello WebSockets!"); 6 }; 7 //接收数据 8 ws.onmessage = function(evt) { 9 console.log( "Received Message: " + evt.data); 10 ws.close(); 11 }; 12 //即将关闭连接 13 ws.onclose = function(evt) { 14 console.log("Connection closed."); 15 };
我们使用ajax时会监听其readyState,当readyState值为4时表示响应已接收并调用回调。
在WebSocket里也有一个常量readyState用来描述 WebSocket 连接的状态。
对应于这几个状态的监听方法有:
WebSocket.onclose()
WebSocket.onerror()
WebSocket.onmessage()
WebSocket.onopen()
在Writing WebSocket client applications这篇websocket实践的文章中提到使用websocket时要注意的一些地方:
*当连接发生错误时,一个命名为“error”的事件会发送到WebSocket实例对象上并触发onerror监听函数。随后CloseEvent事件会发送到WebSocket实例对象上并触发onclose回调函数。
*由于发起连接是异步的,所以WebSocket实例对象的send()方法应该放在onopen()的回调中。
*推荐使用json格式传输数据,考虑到在某些版本的火狐浏览器中,websocket只支持发送字符串。
*WebSocket的api都是事件驱动的,所以我们要习惯用回调的方式处理数据的接收:exampleSocket.onmessage = function (event){//do sth...}
1 // Send text to all users through the server 2 function sendText() { 3 // Construct a msg object containing the data the server needs to process the message from the chat client. 4 var msg = { 5 type: "message", 6 text: document.getElementById("text").value, 7 id: clientID, 8 date: Date.now() 9 }; 10 11 // Send the msg object as a JSON-formatted string. 12 exampleSocket.send(JSON.stringify(msg)); 13 14 // Blank the text input element, ready to receive the next line of text from the user. 15 document.getElementById("text").value = ""; 16 }
三:服务器端的WebSocket
首先看看有哪些支持WebSocket的服务器,这里引用维基百科的资料:
- php - http://code.google.com/p/phpwebsocket/
- jetty - http://jetty.codehaus.org/jetty/(版本7开始支持websocket)[失效链接]
- netty - http://www.jboss.org/netty
- ruby - http://github.com/gimite/web-socket-ruby
- Kaazing - https://web.archive.org/web/20100923224709/http://www.kaazing.org/confluence/display/KAAZING/Home
- Tomcat - http://tomcat.apache.org/(7.0.27支持websocket,建议用tomcat8,7.0.27中的接口已经过时)
- WebLogic - http://www.oracle.com/us/products/middleware/cloud-app-foundation/weblogic/overview/index.html(12.1.2開始支持)[失效链接]
- node.js - https://github.com/Worlize/WebSocket-Node
- node.js - http://socket.io
- nginx - http://nginx.com/
- mojolicious - http://mojolicio.us/
- python - https://github.com/abourget/gevent-socketio
- Django - https://github.com/stephenmcd/django-socketio
- erlang - https://github.com/ninenines/cowboy.git
可见,常见的服务器几乎都支持websocket,我自己学的是node,就研究下node中如何实现websocket。
阮一峰老实在其博客中给出了常用的 Node 实现:
那我就试试Socket.IO吧。
//待续
参考:https://zh.wikipedia.org/wiki/WebSocket