基於 WebSocket 實現 WebGL 3D 拓撲圖實時資料通訊同步(一)

圖撲軟體發表於2016-07-25

今天沒有延續上一篇講的內容,穿插一段小插曲,WebSocket 實時資料通訊同步的問題,今天我們並不是很純粹地講 WebSocket 相關知識,我們通過 WebGL 3D 拓撲圖來呈現一個有趣的 Demo。接下來我們就看看這個實時資料通訊是一個什麼樣的套路。

我們先來聊聊這次 Demo 的思路吧,首先我要有一個 3D 的拓撲圖元件,在上面建立幾個節點,然後通過拉力佈局(ForceLayout)將這些節點自動佈局,但是有一定,需要在不同的網頁視窗下,對應節點的位置是一樣的,簡單地說就是不同網頁視窗所呈現的節點佈局是一樣,而且拖動不同網頁視窗中的任意的節點,都將更新所有頁面視窗,讓所有視窗的呈現都是一樣的。

根據上面的思路,我們該如何去規劃呢?既然需要實時資料通訊,那麼就需要使用 WebSocket,WebSocket 又是什麼呢?WebSocket 是 HTML5 一種新的協議,它沒有標準的 API,各個實現都有自己的一套 API,在這裡我們就不去詳細研究 WebSocket 的具體實現,我也講不了,至少現在講不了。

在這裡我們用比較易上手的 Node.js 的 Socket.IO 做通訊框架,Socket.IO 讓長連線通訊變得無比簡單,伺服器再也不用等待客戶端的請求就可以直接給客戶端傳送訊息,根據這樣的特性就可以實現資料通訊同步的問題。

我們來寫一個最簡單的例子,將任何一個客戶端傳送到伺服器的訊息,原封不動的轉發到所有連線到伺服器的客戶端,我們來看看要實現這樣的一個功能,服務端要怎麼設計。

首先我們得搭建一個簡易的 web 伺服器。

 

var app = require('express')();
var http = require('http').Server(app);

app.get('/', function(req, res) {
    res.end('<h1>Hello Message!</h1>');
});

http.listen(4000, function() {
    console.log('listening on *:4000');
});

 

以上的程式碼的 Node.js 的程式碼,將這串程式碼貼到一個 js 檔案中,比如命名為 server.js 然後在 Terminal 中 cd 到 server.js 對應的資料夾下,如果 node server.js 後回車,如果發現報了 Cannot find module ‘xxx’ 的字樣,那麼說明你在當前目錄下沒有安裝程式用到的相關包。那麼我們在當前目錄下建立一個叫 package.json 的檔案,然後把下面的程式拷貝到該檔案中,然後在 Terminal 中輸入 npm install,等安裝完後,就可以正常啟動伺服器了。

 

{
  "name": "socket-example",
  "version": "0.0.1",
  "description": "my first socket.io app",
  "dependencies": {
    "express": "^4.10.2",
    "socket.io": "^1.4.8"
  }
}

 

啟動後,你在瀏覽器上輸入 localhost:4000 就可以看到 Hello Message! 的字樣。這是最簡單的 HTTP 伺服器,那麼我們如何在上面加上 WebSocket 的功能呢呢?眼尖的同學可能已經發現上面的 package.json 的內容已經包含了 Socket.IO,那麼 Socket.IO 要怎麼用呢,怎麼樣才能達到實時資料通訊的效果呢?

 

var io = require('socket.io')(http);
io.on('connection', function(socket) {
    console.log('a user connected');
    socket.on('disconnect', function() {
        console.log('user disconnected');
    });

    socket.on('message', function(msg) {
        io.emit('message', msg);
    });
});

 

在 server.js 中加入上面那串程式碼,就可以實現客戶端之間的實時資料通訊問題。但是在瀏覽器輸入 localhost:4000 你看到的是 Hello Message! 的字樣,要怎樣才能訪問到具體的 html 網頁內容呢?這個時候就需要稍微修改下我們的伺服器了。

 

app.get('/', function(req, res) {
    res.sendFile(__dirname + '/index.html');
});

 

也就是將前面提到的 res.end('<h1>Hello Message!</h1>’); 程式碼換成 res.sendFile(__dirname + ‘/index.html'); 做個頁面跳轉,從而達到訪問具體 html 網頁的目的,在這邊是是為了滿足 Demo 而做的方案,要搭建一個真正的 http 靜態伺服器肯定不是這樣子的,搭建 http 靜態伺服器我在這邊就不介入研究了,大家剛興趣的話,可以自己到網上搜尋學習。

那麼客戶端該如何實現來展現服務端的實時通訊呢?

 

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Socket.IO Message</title>
        <style media="screen">
            #send { font-size: 14px; }
            #msgList { list-style-type: none; margin: 10px 0px; padding: 0; }
            #msgList li { padding: 5px 10px; }
            #msgList li:nth-child(odd) { background: #eee; }
        </style>
        <script src="/socket.io/socket.io.js"></script>
        <script>
            var socket = io();
            var init = function() {
                var input = document.getElementById('message'),
                    sendFunc = function() {
                        var msg = input.value;
                        if (!msg) return;
                        socket.emit('message', input.value);
                        input.value = '';
                    };

                input.addEventListener('keyup', function(e) {
                    if (e.keyCode === 13) {
                        sendFunc();
                    }
                });

                var list = document.getElementById('msgList');
                socket.on('message', function(msg) {
                    var li = document.createElement('li');
                    li.innerHTML = msg;
                    list.insertBefore(li, list.childNodes[0]);
                });

                var btn = document.getElementById('send');
                btn.addEventListener('click', sendFunc);
            };
        </script>
    </head>
    <body onload="init();">
        Message: <input id="message" />
        <button type="button" id="send">Send</button><br/>
        <ul id="msgList"></ul>
    </body>
</html>

 

以上程式碼就可以做到資料同步了,具體我來解釋下。

頁面很簡單,有一個 input 文字框,和一個 Send 按鈕,還有一個 ul 無序列表用來顯示使用者傳送的內容,當使用者在 input 文字框中輸入內容後,按下 enter 鍵或者點選 Send 按鈕都會想伺服器傳送文字框中填入的內容,並且伺服器會將這條訊息原封不動地推送到所有的客戶端中,在客戶端接收到訊息後,就會想 ul 無序列表中填入訊息。

這個 Demo 在 http://socket.io/get-started/chat/ 這上面比我講得清楚,大家可以到上面詳細閱讀,會理解得更全面一點。

由於篇幅的問題,我今天就介紹到這了,下一篇,我們將重點介紹前面說到的結合 HT for Web 的 3D 拓撲圖元件來展現實時資料通訊的效果,讓每個客戶端都同步操作,效果圖如上。

 

相關文章