HTML5 WebSockets node.js實例教程
譯文HTML 5 中WebSockets是極其重要的部分,它的一個好處之一是減少了不必要的網(wǎng)絡(luò)流量。它主要是用于在客戶機和服務(wù)器之間建立單一的雙向連接。這意味著客戶只需要發(fā)送一個請求到服務(wù)端,那么服務(wù)端則會進(jìn)行處理,處理好后則將其返回給客戶端,客戶端則可以在等待這個時間繼續(xù)去做其他工作,整個過程是異步的。
WebSockets應(yīng)用的場景是很廣泛的,當(dāng)需要實時顯示數(shù)據(jù)的時候(比如股票,實時聊天,對戰(zhàn)游戲等),用戶最期望的是不需要去刷新頁面,否則獲得的用戶體驗是不佳的。而在最新的HTML 5標(biāo)準(zhǔn)中,出現(xiàn)了兩個解決該方面問題的規(guī)范,一個是服務(wù)端推送事件(Server Sent Events),另外一個是WebSockets,其中服務(wù)端推送事件由于在IE 中不能獲得原生支持,因此不在本文討論范圍之中。本文著重講解HTML 5中WebSockets的相關(guān)知識。首先我們還是來復(fù)習(xí)下在HTTP 的網(wǎng)絡(luò)世界中的基本架構(gòu),這是下一步學(xué)習(xí)的基礎(chǔ)。
客戶-服務(wù)器模式是網(wǎng)絡(luò)世界中最經(jīng)典的模式了,能允許多個用戶通過前端圖形界面的方式去,如下圖:
通常,客戶服務(wù)端模式分為兩層和三層。在三層結(jié)構(gòu)中,通常是出現(xiàn)在web應(yīng)用中,中間一層使用了各類的中間件服務(wù)器,分別如下兩圖所示:
我們來看下HTML 5 WebSocket的架構(gòu)圖,如下:
在HTML 5 WebSockets標(biāo)準(zhǔn)中,僅僅定義了一些列的API,這些API用來在客戶端和服務(wù)端之間建立“socket”連接。下面我們來學(xué)習(xí)使用node.js來進(jìn)行WebSockets的學(xué)習(xí)。
首先,到node.js的官網(wǎng)下載node.js,我們選用windows 版本就可以了。
下載安裝包后并選擇socket.io,這只需要在 安裝好的nodejs目錄下,運行命令install就可以了,如圖:
#p#
然后,我們在nodejs目錄下建立一個簡單的js文件,命名為serverfile.js,然后編寫代碼如下:
- var http = require('http');
- var io = require('socket.io');
- var yourserver = http.createServer(function (request, response) {
- response.writeHead(250, { 'Content-Type': 'text/html' });
- response.end('Your WebSocket server is running');
- }).listen(22222);
- var yoursocket = io.listen(yourserver).set('log', 1);
- yoursocket.on('connection', function (client) {
- client.on('message', function (data) {
- console.log('Client Message: ', data);
- var current = new Date().getTime();
- client.emit('YourMessageResponse', data + '->' + current);
- client.on('disconnect', function () {
- console.log('Your Client disconnected');
- });
- });
- });
然后重新在nodejs的目錄中輸入如下圖的命令,以啟動服務(wù)端:
這樣,服務(wù)端就已經(jīng)啟動了,下面來編寫客戶端,客戶端其實就是一個簡單的html頁面,代碼如下:
- <!DOCTYPE html>
- <html>
- <head>
- <script src='http://localhost:22222/socket.io/socket.io.js'></script>
- </head>
- <body>
- <script>
- var HTML5WebSockets = {};
- HTML5WebSockets.socketio = {
- yoursocket: null,
- initialize: function () {
- HTML5WebSockets.socketio.yoursocket = io.connect('http://localhost:22222');
- HTML5WebSockets.socketio.yoursocket.on('connect', function () {
- HTML5WebSockets.socketio.log('You are connected to Server<br />');
- });
- HTML5WebSockets.socketio.yoursocket.on('message', function (data) {
- HTML5WebSockets.socketio.log('Server Response: ' + data + '<br />');
- });
- HTML5WebSockets.socketio.yoursocket.on('disconnect', function () {
- HTML5WebSockets.socketio.log('You are disconnected from Server<br />');
- });
- document.querySelector('#sendMes').onclick = function () {
- HTML5WebSockets.socketio.sendMessageToServer(document.querySelector('#mes').value);
- document.querySelector('#mes').value = '';
- };
- },
- sendMessageToServer: function (data) {
- HTML5WebSockets.socketio.yoursocket.send(data);
- HTML5WebSockets.socketio.log('Message to Server: ' + data + '<br />');
- },
- log: function (message) {
- document.querySelector('#log').innerHTML += message;
- }
- }
- </script>
- <div id='log'></div>
- <input type='text' id='mes' />
- <button type='button' id='sendMes'>Send</button>
- <br />
- <script>
- HTML5WebSockets.socketio.initialize();
- </script>
- </body>
- </html>
現(xiàn)在假設(shè)服務(wù)端已經(jīng)運行后,我們可以直接在瀏覽器中輸入網(wǎng)址運行,如下圖:
這個時候表示客戶端已經(jīng)和服務(wù)端連接上了(這個時候調(diào)用的是
HTML5WebSockets.socketio.yoursocket.on的方法)。
接下來我們在文本框中輸入一些要發(fā)送到服務(wù)端的信息,并點Send按鈕,則可以從日志信息中看到信息發(fā)送到服務(wù)端的提示,如下兩圖所示:
同時我們也觀察下服務(wù)端的控制臺的輸出,如下所示:
可以看到服務(wù)端正確收到了來自客戶段的請求信息。
從上面的例子可以看到,node.js由于使用了Socket.io 模塊,大大減輕了使用WebSocket的難度,可以說是為WebSocket而生的。
接下來,我們看下如何對客戶端進(jìn)行廣播消息?所謂的廣播消息,就是將某個消息在同一時間發(fā)送給已連接服務(wù)端的所有客戶端,所有客戶端都能收到該消息。下面我們動手改造下服務(wù)端的代碼如下:
- var http = require('http');
- var io = require('socket.io');
- var yourserver = http.createServer(function (request, response) {
- response.writeHead(250, { 'Content-Type': 'text/html' });
- response.end('Your WebSocket server is running');
- }).listen(22222);
- var yoursocket = io.listen(yourserver).set('log', 1);
- yoursocket.on('connection', function (client) {
- client.on('YourcustomMessage', function (data) {
- console.log('Client Custom Message: ', data);
- var current = new Date().getTime();
- client.broadcast.emit('YourMessageResponse', data + '(broadcasted)->' + current);
- });
- client.on('disconnect', function () {
- console.log('Your Client disconnected');
- });
- });
#p#
可以看到,唯一和之前服務(wù)端代碼不同的是使用了client.broadcast.emit方法,可以從Socket.IO 服務(wù)器將廣播消息發(fā)送給客戶端。并且為了驗證我們是在同一時刻發(fā)送相同的消息給各個客戶端,我們設(shè)置了當(dāng)前的時間到current變量進(jìn)行返回。我們可以將該文件另存為serverfile2.js。然后同樣按上文的方法啟動服務(wù)端。
接下來編寫客戶端代碼如下:
- <!DOCTYPE html>
- <html>
- <head>
- <script src='http://localhost:22222/socket.io/socket.io.js'></script>
- </head>
- <body>
- <script>
- var HTML5WebSockets = {};
- HTML5WebSockets.socketio = {
- yoursocket: null,
- initialize: function () {
- HTML5WebSockets.socketio.yoursocket = io.connect('http://localhost:22222');
- HTML5WebSockets.socketio.yoursocket.on('connect', function () {
- HTML5WebSockets.socketio.log('You are connected to Server<br />');
- });
- HTML5WebSockets.socketio.yoursocket.on('YourMessageResponse', function (data) {
- HTML5WebSockets.socketio.log('Server Custom Response: ' + data + '<br />');
- });
- HTML5WebSockets.socketio.yoursocket.on('disconnect', function () {
- HTML5WebSockets.socketio.log('You are disconnected from Server<br />');
- });
- document.querySelector('#sendCustMes').onclick = function () {
- HTML5WebSockets.socketio.emitCustomMessageToServer(document.querySelector('#custMes').value);
- document.querySelector('#custMes').value = '';
- };
- },
- emitCustomMessageToServer: function (data) {
- HTML5WebSockets.socketio.yoursocket.emit('YourcustomMessage', data);
- HTML5WebSockets.socketio.log('Custom message to Server: ' + data + '<br />');
- },
- log: function (message) {
- document.querySelector('#log').innerHTML += message;
- }
- }
- </script>
- <div id='log'></div>
- <input type='text' id='custMes' />
- <button type='button' id='sendCustMes'>Brodcast</button>
- <script>
- HTML5WebSockets.socketio.initialize();
- </script>
- </body>
- </html>
可以看到客戶端的代碼并沒有多大變化。接下來我們同時啟動多個瀏覽器打開這個客戶端的文件,如下圖:
這表明各個客戶端都已經(jīng)連接上服務(wù)端了,然后在其中的一個客戶端頁面中輸入任意內(nèi)容,點發(fā)送,則可以看到服務(wù)端的nodejs控制臺收到了該消息,并且同時將當(dāng)前時間附加到消息中,同時發(fā)送到各請求的客戶端,實現(xiàn)了廣播的功能,如下圖:
讀者可以進(jìn)一步對上面的nodejs例子進(jìn)行改造,就可以很容易實現(xiàn)如各類實時應(yīng)用了。