socket.io
Socket.IO 是一個用於建立即時性通訊網頁應用程式(realtime web applications)的跨平台 JavaScript 函式庫,可以消除不同平台上傳輸方式的差異性,讓開發者更容易發展即時性的網頁應用程式。
Socket.IO 包含瀏覽器端函式庫(client-side library,運行於瀏覽器中)與伺服器端函式庫(server-side library,運行於 Node.js 環境),而兩者所提供的 API 幾乎相同。
在傳輸的方式上,Socket.IO 使用 WebSocket 作為主要的傳輸協定,而在某些瀏覽器不支援 WebSocket 的狀況下,則會自動改用其他的方式來傳輸(如 Adobe Flash sockets、JSONP polling 與 AJAX long polling 等),至於 API 的使用方式則維持不變,也就是說開發者可以不必考慮該使用哪一種傳輸方式,Socket.IO 會自動選擇一個最適合的來使用。
在大部分新的瀏覽器中,Socket.IO 其實都是使用 WebSocket 來傳輸,所以 Socket.IO 也可以視為一個 WebSocket 的包裝工具,但是他所提供的功能比 WebSocket 還要豐富,例如 Socket.IO 的 heartbeats、timeouts 與 disconnection 等功能對於即時性的應用程式而言都是很重要的,但是原生的 WebSocket API 卻沒有這些功能。
安裝 Node.js 與 Socket.IO
npm install socket.io
基本 Server
var http = require('http');
var server = http.createServer(function(request, response){
console.log('Connection');
response.writeHead(200, {'Content-Type': 'text/html'});
response.write('Hello, World.');
response.end();
});
server.listen(8001);
接著執行 node server.js,然後用瀏覽器打開 http://localhost:8001/ 這個網址,就可以看到 Hello, World. 字串顯示在瀏覽器上了。(如果你是在遠端的伺服器上測試,就把 localhost 改成對應的 IP 位址即可)
如果想要架一個像樣的server可以使用express module,這裡主要是介紹簡單的server跟socket.io
接下來我們詳細說明一下上面這段程式碼的細節,首先是使用 http.createServer 建立伺服器的部份:
var server = http.createServer(function(request, response){});
server.listen(8001);
這裡放的匿名函數(anonymous function)是用來定義當伺服器接收到請求時,該做什麼事情,以及該如何回應。
接著使用 response.writeHead() 設定 HTTP 回應的標頭資訊:
response.writeHead(200, {'Content-Type': 'text/html'});
再來是送response body:
response.write('Hello, World.');
最後結束整個定義過程:
response.end()
加入 Socket.IO
接著我們建立一個 socket.html 檔案,內容如下:
<html>
<head></head>
<body>This is our socket.html file</body>
</html>
建立一個socket.io server
var http = require("http");
var url = require('url');
var fs = require('fs');
var io = require('socket.io'); // 加入 Socket.IO
var server = http.createServer(function(request, response) {
console.log('Connection');
var path = url.parse(request.url).pathname;
switch (path) {
case '/':
response.writeHead(200, {'Content-Type': 'text/html'});
response.write('Hello, World.');
response.end();
break;
case '/socket.html':
fs.readFile(__dirname + path, function(error, data) {
if (error){
response.writeHead(404);
response.write("opps this doesn't exist - 404");
} else {
response.writeHead(200, {"Content-Type": "text/html"});
response.write(data, "utf8");
}
response.end();
});
break;
default:
response.writeHead(404);
response.write("opps this doesn't exist - 404");
response.end();
break;
}
});
server.listen(8001);
io.listen(server); // 開啟 Socket.IO 的 listener
這裡只有更動兩個小地方而已,一個是在上方引入 socket.io 模組,例外在最後一行開啟一個 Socket.IO 的 listener,讓伺服器啟動時就可以準備接收來自於瀏覽器的 WebSocket 連線。
現在當我們重新執行 node server.js 之後,瀏覽 http://localhost:8001/socket.html 這個網址時,在瀏覽器端沒有什麼變化,但是在伺服器的終端機中則會出現
接著我們要修改 socket.html 的內容,加入 Socket.IO 的連線功能,讓瀏覽器可以透過 WebSocket 連線到我們剛剛寫好的伺服器上。以下是 socket.html 的內容:
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<script>
var socket = io.connect();
</script>
<div>This is our socket.html file</div>
</body>
</html>
這裡我們在網頁中引入了 Socket.IO 的 JavaScript 檔,並且呼叫 io.connect() 連線至伺服器,這時候如果重新載入這個網頁,你就可以在伺服器的終端機中看到類似下面這幾行資訊:
info - socket.io started
debug - served static content /socket.io.js
debug - client authorized
info - handshake authorized 1agc6iSouA2QymxUaZ0D
debug - setting request GET /socket.io/1/websocket/1agc6iSouA2QymxUaZ0D
debug - set heartbeat interval for client 1agc6iSouA2QymxUaZ0D
debug - client authorized for
debug - websocket writing 1::
現在我們已經成功建立了一個伺服器與瀏覽器之間的 WebSocket 連線了,下面我們繼續示範如何讓伺服器透過這個連線傳送資料給瀏覽器。
傳送資料至瀏覽器
Socket.IO 傳送資料的方式跟一般 Node.js 程式所使用的方式差不多,都是以回呼函數的方式來處理,這裡我們使用 on() 函數將特定的事件連接到指定的匿名函數,藉此定義整個資料傳輸過程要如何運作。
現在我們在 server.js 的最後,將 io.listen() 的傳回值儲存起來,並加入一小段程式碼:
var serv_io = io.listen(server);
serv_io.sockets.on('connection', function(socket) {
socket.emit('message', {'message': 'hello world'});
});
這裡我們使用 on() 函數將 connection 事件與一個匿名函數連接起來,這樣只要 WebSocket 連線一建立,這個匿名函數就會被呼叫。
這裡的 connection 是一個由 Socket.IO 內建的事件,當瀏覽器端呼叫 io.connection() 之後,就會自動產生這個事件,進而呼叫上面這個匿名函數,而我們也可以自行定義事件,這裡馬上就有一個例子。
在這個匿名函數中,當連線建立之後,我們使用 emit() 函數來傳送資料,這個函數在伺服器與瀏覽器端的用法是一樣的,作用就是將資料傳給對方。
emit() 會產生一個事件,而其事件的名稱是透過第一個參數來定義的(以這個例子來說就是 message,當然你也可以使用其他的名稱),而第二個參數則是指定這個事件所伴隨的資料,而這個資料的格式則是一個 JSON 的物件。
到這裡我們已經設定好在連線建立之後,讓伺服器送出一個訊息,接下來我們還要讓瀏覽器接收這段訊息才行,我們將 socket.html 修改一下:
var socket = io.connect();
socket.on('message', function(data){
console.log(data.message);
});
我們在這裡也同樣使用 on() 函數連接一個匿名函數,讓臉器可以接收來自於伺服器的訊息(也就是接收由伺服器所產生的 message 事件),然後呼叫 console.log() 函數將訊息輸出在瀏覽器的 console 中。
現在重新啟動 server.js 與重新整理瀏覽器之後,開啓瀏覽器的 JavaScript 除錯視窗,應該就會發現 hello world 出現在瀏覽器的 console 中了。