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 中了。

Reference

results matching ""

    No results matching ""