最近因为有需要开发互动式网页,而且又需要频繁地和server端坐沟通,所以除了ajax之外,也开始研究一些新的东西;而其中一个,就是可以更节省频宽的WebSocket、这个HTML 5的通讯方法了~
关于WebSocket的介绍,建议庆直接参考维基百科,或是WebSocket.org的介绍;完整的API则可以参考W3C的网页。在Heresy来看,WebSocket和传统的HTML数据取得的方法相比,最大的好处,就是由于WebSocket是建立一个持续性的连线,不需要重复地不断建立连线,所以可以有效地降低延迟、并且减少数据的传输辆。
像右图就是WebSocket.org所提供的示意图,可以看到随着要求存取的次数的增加,传统的「Polling」的数据存取方法所需的频宽会上升地非常地快;相较之下,WebSocket的频宽则可以省非常地多。
另外,由于WebSocket在建立后,可以真正地由Server端主动送数据给client(浏览器),所以也可以避免掉一来一往之间的延迟。下方就是WebSocket.org的示意图:
而目前支援WebSocket的浏览器列表,可以参考:Can I Use这个网页或维基百科。基本上,主要的浏览器,只要版本够新,都是有支援的;比较大的问题,应该会是IE要到10.0才有支援,而Android内建的浏览器则完全没有支援。
WebSocket的Client端,一般就是使用JavaScript来做撰写,然后在浏览器内执行;他的基本使用也相当简单,在WebSocket.org的网站里,就有提供一个「Echo Test」的网页,算是可以做最基本的说明了~他的范例源代码如下(Heresy自己有略做修改):
<! DOCTYPE html > < html > < head > < meta charset = "utf-8" /> < title > WebSocket Test </ title > < script language = "javascript" type = "text/javascript" > var wsUri = " ws:// echo.websocket.org /" ; var output; function init() { output = document.getElementById( "output" ); testWebSocket(); } function testWebSocket() { websocket = new WebSocket(wsUri); websocket.onopen = function (evt) { onOpen(evt) }; websocket.onclose = function (evt) { onClose(evt) }; websocket.onmessage = function (evt) { onMessage(evt) }; websocket.onerror = function (evt) { onError(evt) }; } function onOpen(evt) { writeToScreen( "CONNECTED" ); doSend( "WebSocket rocks" ); } function onClose(evt) { writeToScreen( "DISCONNECTED" ); } function onMessage(evt) { writeToScreen( '<span style="color:blue;">RESPONSE:' + evt.data + '</span>' ); websocket.close (); } function onError(evt) { writeToScreen( '<span style="color:red;">ERROR:</span>' + evt.data ); } function doSend(message) { writeToScreen( "SENT: " + message); websocket.send(message ); } function writeToScreen(message) { var pre = document.createElement( "p" ); pre.style.wordWrap = "break-word" ; pre.innerHTML = message; output.appendChild(pre); } window.addEventListener( "load" , init, false ); </ script > </ head > < body > < h2 > WebSocket Test </ h2 > < div id = "output" ></ div > </ body > < / html >
首先,在这个网页里面,HTML的部分相当简单,就是一个<H2>的标题,和一个id为「output」的<div>,用来做输出之用。而在网页载入完成后,他会去执行JavaScript的init()这个函数,开始进行WebSocket的测试。
实际上WebSocket测试的程序,是写在testWebSocket()这个函数里,它的使用方法相当单纯,首先就是要建立一个WebSocket的物件,也就是:
websocket = new WebSocket(wsUri);
在这边,传入的字串wsUri的内容是「ws:// echo.websocket.org /」,目的是告诉浏览器,这个WebSoscket是要连到哪里;在这边,就是连到WebSocket.org提供的测试Server。而这个URI前面的「ws://」,则是代表要使用WebSocket这种通讯协议,如果要使用加密的连线的话,则是要改成「wss://」。
后面的网址的部分,则也可以再加上连接埠、或是其他的路径,来当作进一步的数据;例如:「ws://localhost:12345/websocket/ server.php」也是一种合法的URI (参考)。
而之后,这个建立出来的websocket物件,会有四种事件,分别为:
onopen
当连线建立时,会被触??发的事件
onmessage
当收到Server 端发送的信息时,会被触??发的事件
onclose
连线中断时会被触发的事件
onerror
出现错误时会被触发的事件
这边基本上就是要针对这四种事件,来做设置,让程序可以在事件发生时,做对应的动作。像在上面的范例程序里,就是设置当这四种事件被触发的时候,会去调用对应的函数(例如,当onopen的事件触发的时候,就去调用onOpen()这个函数)。
而这个范例网页用浏览器打开后,基本上应该会看到下面的结果:
WebSocket Test
CONNECTED SENT: WebSocket rocks RESPONSE: WebSocket rocks/message DISCONNECTED
整个程序执行的流程,大致如下:
首先,当建立了一个WebSocket连线后,接下来通常都会是因为能正确地连线,所以会出发到onopen的事件,所以会去执行onOpen()这个函数;而这个函数所做的事,就是先输出一个「CONNECTED」的字串,然后再调用doSend()这个函数,送出「WebSocket rocks」这个字串。
而实际上,要通过WebSocket来送出信息,也相当简单,只要调用WebSocket物件(websocket)的send()这个函数就可以了~
接下来,Server端的部分,应该是设计成在收到client端送来的信息后,就原封不动地,把信息再送回给client端,所以接下来,这个网页就会因为收到Server端送来的信息,而触发到onmessage的事件,进而调用onMessage()这个函数。
而在这个范例程序里,在收到Server端送来的信息(evt)后,就会把他的数据(evt.data)作输出(上面蓝色的字),并且调用WebSocket的close()函数,把这个连线给关闭。
而由于连线被关闭了,所以接下来则是会触发到onclose的事件、进而执行onClose()这个函数;在这个函数里,基本上就是很简单地输出「DISCONNECTED」这个字串。
所以到上面为止,就是这个范例的基本概念了~基本上,他是在连线后、传递、接收一个信息后,马上就把连线断掉了;而如果再做修改,让他可以持续地送信息的话,就可以做到「echo test」这个范例网页里,可以持续传递、接收数据的功能了~而实际上,WebSocket的client端程序,大概也就是以这样的概念来写了。
另外,onmessage所收到的数据,实际上是一个MessageEvent的物件,它除了可以接收字串型别的数据外,其实也是可以接收Blob(参考)和ArrayBuffer(参考)这两种形式的数据,所以在技术上,其实WebSocket是可以用来传输相当复杂的东西的~