使用 NodeJS + Express + Socket.IO 實作 WebSocket 服務
一直處於假標準狀態的 HTML5,過程中一直有變化,讓人無法放心使用。不過到了今年,HTML5 總算進入了準決賽的階段,大部份功能已經確定下來,其中 WebSocket 就是最讓人關切的項目之一,因為這意味著未來 Web 不再只是單次性的觸發服務,而是可以讓使用者端與伺服器長時間處於連線狀態,並進行即時性的資料傳交換。
關於 WebSocket,彷間許多隨 HTML5 起舞的人,其實都說明不夠清楚,多半只強調能達成 TCP Socket 形式的連線,和無所不能的優點。其實,WebSocket 並非是我們所知的原生 Socket ,而只是一種架構於 HTTP Protocol 上的延伸定義,所以換句話來說,不能直接拿來連線到非 HTTP 以外的通訊協定。
至於它的做法,就是在瀏覽器向伺服器要資料時,在 Request Header 裡加上『Connection:Upgrade』來告訴伺服器:『我要改變連線形態』。然後伺服器會依照瀏覽器給的 WebSocket 相關標頭(header)和交握用的金鑰(Key),進行認證和改變處理方式。進入 WebSocket 連線的客戶端,就有如在使用 TCP Socket 或 Telnet 一樣,可以隨意在任意時間點傳送資料給伺服器處理,伺服器也可以在這連線下即時回應。所以就某方面來說,這剛好可以含蓋並取代過去 Web 1.0 的 Refresh Page 和 Web 2.0 後的 Long-polling 技術。
寫過網路程式的人都知道,如何定義 Protocol 才是傷腦筋的事,開啟了一個『類 Socket』意味著我們又回到了過去的年代,要自己解決 Protocol 的定義。不過也已經有現成的 Library 可以使用,許多問題我們已經不用擔心,本文將提到的 Socket.IO 就是其中之一。此外,由於 WebSocket 需要 Client/Server 同時實作,所以,這些 Library 多半都包括了兩部份的實作。
Server 端,使用 NodeJS + Express web framework + Socket.IO(0.8.6):
Client 端,使用 Socket.IO(0.8.6):
後記
回到原始的網路溝通,也有許多議題將再次面臨,舉例來說,客戶端(Client)可以同時發送很多道命令給伺服器,但伺服器可能每道命令完成時間有快有慢,以至有些命令是後發卻先完成。那伺服器如何告知客戶端,是哪一道命令完成了?而這種問題非常容易在多功能的服務中見到,尤其是遊戲伺服器。不過,對於過去有過伺服器設計經驗的人,顯然是不用怕。
備註:使用 Socket.IO 要注意版本的變化,因為各版 API 改動伏度都不小。而且也要注意 Client/Server 要使用同一版本,之前筆者犯錯,在 Client 使用官方提供的 CDN 版本,但在 Server 端使用自己下載的最新版本,結果一直無法讓 WebSocket 成功被建立。
關於 WebSocket,彷間許多隨 HTML5 起舞的人,其實都說明不夠清楚,多半只強調能達成 TCP Socket 形式的連線,和無所不能的優點。其實,WebSocket 並非是我們所知的原生 Socket ,而只是一種架構於 HTTP Protocol 上的延伸定義,所以換句話來說,不能直接拿來連線到非 HTTP 以外的通訊協定。
至於它的做法,就是在瀏覽器向伺服器要資料時,在 Request Header 裡加上『Connection:Upgrade』來告訴伺服器:『我要改變連線形態』。然後伺服器會依照瀏覽器給的 WebSocket 相關標頭(header)和交握用的金鑰(Key),進行認證和改變處理方式。進入 WebSocket 連線的客戶端,就有如在使用 TCP Socket 或 Telnet 一樣,可以隨意在任意時間點傳送資料給伺服器處理,伺服器也可以在這連線下即時回應。所以就某方面來說,這剛好可以含蓋並取代過去 Web 1.0 的 Refresh Page 和 Web 2.0 後的 Long-polling 技術。
寫過網路程式的人都知道,如何定義 Protocol 才是傷腦筋的事,開啟了一個『類 Socket』意味著我們又回到了過去的年代,要自己解決 Protocol 的定義。不過也已經有現成的 Library 可以使用,許多問題我們已經不用擔心,本文將提到的 Socket.IO 就是其中之一。此外,由於 WebSocket 需要 Client/Server 同時實作,所以,這些 Library 多半都包括了兩部份的實作。
Server 端,使用 NodeJS + Express web framework + Socket.IO(0.8.6):
/* Module dependencies */ var express = require('express'); var io = require('socket.io'); /* Initializing Express Framework */ var app = module.exports = express.createServer(); app.listen(3000); /* Create a Socket.IO instance, to establish WebSocket Service */ var socket = io.listen(app); socket .on('connection', function(client) { console.log('A connection was established'); client .on('pretty-girl', function(data) { console.log(data); socket.emit('ugly-man', 'get out of my way'); }); client.on('disconnect', function() { console.log('Server has disconnected'); }); });
Client 端,使用 Socket.IO(0.8.6):
socket = io.connect(); socket.on('connect', function() { console.log('Client has connected to the server!'); }) socket.on('disconnect', function() { console.log('The client has disconnected!'); }); socket.on('ugly-man', function(data) { console.log(data); }); socket.emit('pretty-girl', 'hello!');
後記
回到原始的網路溝通,也有許多議題將再次面臨,舉例來說,客戶端(Client)可以同時發送很多道命令給伺服器,但伺服器可能每道命令完成時間有快有慢,以至有些命令是後發卻先完成。那伺服器如何告知客戶端,是哪一道命令完成了?而這種問題非常容易在多功能的服務中見到,尤其是遊戲伺服器。不過,對於過去有過伺服器設計經驗的人,顯然是不用怕。
備註:使用 Socket.IO 要注意版本的變化,因為各版 API 改動伏度都不小。而且也要注意 Client/Server 要使用同一版本,之前筆者犯錯,在 Client 使用官方提供的 CDN 版本,但在 Server 端使用自己下載的最新版本,結果一直無法讓 WebSocket 成功被建立。
留言
張貼留言