iT邦幫忙

DAY 2
9

且戰且走HTML5系列 第 2

且戰且走HTML5(2) 應用主軸:WebSocket

WebSocket是瀏覽器與伺服器交換資料的方式之一,與HTTP最大的不同是,他是一個持續的雙向的連線,所以沒有重新連線,重新傳送檔頭等多餘的負荷,反應更即時。
WebSocket實際上分成兩個部分,一個是瀏覽器上的程式介面,另外一個是伺服器端的傳輸協定標準。WebSocket傳輸協定已經在今年(2012)成為IETF的正式標準:RFC 6455,從各方面來說,也已經是一個成熟的技術了。IE10、Safari6、Chrome16、Firefox11、Opera12.10等瀏覽器,也都會支援正式的標準。不過IE要到10才支援WebSocket,其他瀏覽器較舊的版本,則可能會支援不同草案版本的WebSocket。這方面可以參考Wikipedia: WebSocket

如果不管伺服器,WebSocket在瀏覽器的使用是非常簡單的,因為他只有兩個動作:收、發。在使用前,需要建立一個WebSocket物件,把要Access的WebSocket網址傳給他:

  var ws = new WebSocket('ws://127.0.0.1:8443/chat');
  ws.onmessage = function(message) {alert(message.data);ws.close()};
  ws.send('Hello WebSocket.');

WebSocket可以選擇ws或是wss通訊協定,ws就相當於一般的http,wss則相當於https,不過需要伺服器可以支援。其他部分使用起來,就如同一般的URL。另外,由於時持續的連線,所以在連線中URI是不會改的,所以每次也只能選擇一個URI,想跟不同URI連線,就需要建立新的WebSocket連線。

只要用send()就可以送出資料。接收資料則可以利用WebSocket的onmessage事件,資料可以透過上述程式示範中的方式取得。呼叫close()就可以結束連線。基本使用就是這樣了,真的很簡單。

除了onmessage事件,WebSocket API還支援了onopen/onclose/onerror等事件。(顧名可思義,不必多說了吧?)另外有幾個屬性可以使用,readyState就類似XMLHttpRequest的readyState,有CONNECTING/OPEN/CLOSING/CLOSED四個狀態可以查詢WebSocket目前的狀態。bufferedAmount屬性,可以取得目前有多少byte的資料尚未送出的資訊。如果傳送的資訊比較多,或是網路速度比較慢時,就可以使用他來確認前一次送出的資料到底送完沒。不過簡單的應用通常不需要擔心,因為傳送的速度應該很快。

WebSocket這個Constructor其實還有一個可省略的參數:protocol,可以指定伺服器要使用怎樣的sub protocol。例如:

  var ws = new WebSocket('ws://127.0.0.1:8443/wamp', 'wamp');

另外透過protocol屬性,也可以知道目前使用的protocol(由於可以提供多個protocal給伺服器選擇,所以這個屬性)。使用sub protocol,可以把特定的應用包裝成標準的使用方法,透過支援的library,就可以不管WebSocket的運作,而專注在應用上。

目前已經有一些sub protocol應用,例如:WAMP(The Websocket Application Messaging Protocol)。不過如果不是有建立應用「標準」的需求,通常不太需要使用這個。

在伺服器方面,就比較複雜了,因為需要實作整個WebSocket Protocol...不過一般來說我們不會這樣用,而是使用支援WebSocket的Library。大致介紹一下WebSocket大致上定義了哪些東西。

首先就是交握(handshake),這其實是跟HTTP格式相容的標頭(header),裡面含有WebSocket定義的header資訊,伺服器必須處理這些資訊,然後在回應的標頭中回應處理過的結果。瀏覽器檢驗過伺服器回傳的標頭,雙方就可以建立資料連結,傳送資訊,直到呼叫close()為止。

WebSocket中資料傳送的單位叫做Frame,目前RFC 6455中定義了幾種frame:text data、binary data、ping/pong、close等,所以應該可以傳送文字跟binary資料、透過ping/pong來做heartbeat等,close則是用來做關閉連線的通知。另外,為了支援傳送未知長度的資料,frame還可以做分割以分批傳送。

這些要自己寫有點複雜,所以在伺服器端還是使用別人實作好的Library。由於伺服器端我想使用node.js,所以就選擇最多人使用的Socket.IO...這些等明天來介紹吧。


上一篇
且戰且走HTML5(1) 前言:為何且戰且走
下一篇
且戰且走HTML5(3) 使用Socket.io
系列文
且戰且走HTML530
0
ted99tw
iT邦高手 1 級 ‧ 2012-10-10 09:49:24

沙發

我太會喇賽的結果導致俺一天可用“討論”次數只剩下個位數,但不管剩下多少,也要在費大公這邊抛頭顱灑熱寫啦~~~

我也要喜歡

0
海綿寶寶
iT邦超人 1 級 ‧ 2012-10-10 10:36:40

請教費大

這個WebSocket是否只能應用在實體 IP 連線
疑惑

如果我是公司的內部IP 10.10.x.x
連外的IP是 74.53.124.253
WebServer 的 IP 是 118.214.231.77
如此 WebSocke 是否可以適用
謝謝

看更多先前的回應...收起先前的回應...
fillano iT邦超人 1 級‧ 2012-10-10 22:29:28 檢舉

一般來說應該可以,基本上他跟http是一樣的。

其實明天介紹的Socket.IO作者,有做過一些Survey:https://github.com/LearnBoost/socket.io/wiki/Socket.IO-and-firewall-software

**fillanohttps://github.com/LearnBoost/socket.io/wiki/Socket.IO-and-firewall-software**提到:
一般來說應該可以,基本上他跟http是一樣的。

了解
是我的問題沒問清楚
我的問題是
這個WebSocket是否如同HTTP
是由HTTP client發Request給Server然後Server回覆
有沒有
由Server主動發送資料給Client的模式
臉紅

fillano iT邦超人 1 級‧ 2012-10-10 22:46:57 檢舉

我解釋一下建立WebSocket連線的過程:

  1. Client送出Request,Request Header裡面會有handshake需要的資訊。如果資訊驗證有問題,Server就會中斷連線
  2. Server收到Request後,會送出一個Response Header,讓Client根據裡面的資訊做驗證
  3. Client驗證OK,之後就繼續連線,Client可以透過這個連線送資料給Server,Server也可以透過這個連線送資料給Client,任何一方都可以透過這個連線送資料
  4. Client驗證有錯,就中斷連線

所以,連線這個動作必須要Client發起,但是之後的資訊傳輸,就沒有限制。

fillano提到:
Client可以透過這個連線送資料給Server,Server也可以透過這個連線送資料給Client,任何一方都可以透過這個連線送資料

如果是這樣的話
這應該算是重大改變了
忙

0
逮丸逮丸
iT邦大師 1 級 ‧ 2012-10-10 21:32:58

會介紹publish subscribe嗎?
好像要用到 publish subscribe 機制的方案,
是否一定避免不了「非port 80」的情況?
這是我一直搞不清楚的。

1
fillano
iT邦超人 1 級 ‧ 2012-10-10 22:39:34

我是沒用到pub sub pattern來做,不過基本上WebSocket是與http相容的。以node.js為例,除了Socket.IO之外,有許多WebSocket模組也都支援把WebSocket附加到http伺服器,讓同一個port(ex: 80)可以同時支援http以及WebSocket。

其實在request送達時,只要針對Request Header做過濾,就可以同時支援http跟WebSocket。差別在於,http在送出response之後就會斷線,而WebSocket在送出Response Header之後並不會斷線,除非handshake沒過,之後就透過相同的連線雙向傳送資料,直到一方斷線為止。

fillano iT邦超人 1 級‧ 2012-10-10 22:40:37 檢舉

阿?按錯按鈕...我應該按「回應」的說XD

按討論也好
才會顯示有更新
原發問人才知道大師有來回覆了
筆記

我要留言

立即登入留言