1. 程式人生 > >實時通訊之Socket.io

實時通訊之Socket.io

WebSocket WebSocket是HTML5開始提供的一種瀏覽器與伺服器間進行全雙工通訊的網路技術。使用WebSocket,瀏覽器和伺服器只需要要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道,兩者之間就直接可以資料互相傳送。而且它為我們實現即時服務帶來了兩大好處:
  • 節省資源:互相溝通的Header是很小的-大概只有 2 Bytes。
  • 推送資訊:不需要客戶端請求,伺服器可以主動傳送資料給客戶端。
socket.io Socket.IO是一個WebSocket庫,包括了客戶端的js和伺服器端的nodejs,它的目標是構建可以在不同瀏覽器和移動裝置上使用的實時應用。 服務監聽
socket.io的服務端啟動非常的簡單,引用socket.io模組。然後呼叫listen函式,傳入監聽的埠號,開始服務監聽。 var io =require('socket.io')(80); 註冊事件 connection事件在客戶端成功連線到服務端時觸發,有了這個事件,我們可以隨時掌握使用者連線到服務端的資訊。 當客戶端成功建立連線時,在connection事件的回撥函式中,我們還是可以為socket註冊一些常用的事件,如:disconnect事件,它在客戶端連線斷開是觸發,這時候我就知道使用者已經離開了。 var io =require('socket.io')(80); io.on
('connection',function(socket){ //連線成功... socket.on('disconnect',function(){ //使用者已經離開... }); }); 啟動服務 為了在瀏覽器中能夠訪問到我們的服務,我們還需要在服務端搭建一個簡單的web伺服器,讓瀏覽器能夠訪問我們的客戶端頁面。 為了便捷,我們選用node.js中常用的express框架來實現web服務,示例如下: var express =require('express'); var app = express(); app.get('/',function(req,res){ res.status(200
).send('歡迎!'); }); var server =require('http').createServer(app); var io =require('socket.io')(server); io.on('connection',function(socket){ }); server.listen(80); 客戶端引用 服務端執行後會在根目錄動態生成socket.io的客戶端js檔案,客戶端可以通過固定路徑/socket.io/socket.io.js新增引用。 首先新增網頁index.html,並在網頁中引用客戶端js檔案: <scriptsrc="/socket.io/socket.io.js"></script> 當然這樣的客戶端引用方式並不是必須的,我們也可以引用官方的cdn或者下載到本地的客戶端檔案。一般情況下推薦引用動態生成的客戶端檔案,因為這樣客戶端和服務端的版本可以保持一致,減少出錯的機率。 <script src="https://cdn.socket.io/socket.io-1.2.1.js"></script> 連線服務 當客戶端成功載入socket.io客戶端檔案後會獲取到一個全域性物件io,我們將通過io.connect函式來向服務端發起連線請求。 var socket = io.connect('/'); socket.on('connect',function(){ //連線成功 }); socket.on('disconnect',function(data){ //連線斷開 }); connect函式可以接受一個url引數,url可以socket服務的http完整地址,也可以是相對路徑,如果省略則表示預設連線當前路徑。與服務端類似,客戶端也需要註冊相應的事件來捕獲資訊,不同的是客戶端連線成功的事件是connect。 實時通訊 當我們成功建立連線後,我們可以通過socket物件的send函式來互相傳送訊息,示例-客戶端向服務端傳送訊息(index.html): var socket = io.connect('/'); socket.on('connect',function(){ //客戶端連線成功後傳送訊息'hello world!' socket.send('hello world!'); }); socket.on('message',function(data){ alert(data); }); 連線成功後,我們向服務端傳送訊息hello world!,還為socket註冊了message事件,它是send函式對應的接收訊息的事件,當服務端向客戶端send訊息時,我們就可以在message事件中接收到傳送過來的訊息。 服務端向客戶端傳送訊息也可以通過send的方式,示例 - 服務端向客戶端傳送訊息(app.js): var io =require('scoket.io'); io.on('connection',function(socket){ socket.send('歡迎!'); socket.on('message',function(data){ //收到訊息 console.log(data); }); }); 與客戶端相同,服務端也需要為socket註冊message事件來接收客戶端傳送過來的訊息。 傳送資訊 socket.io既然是用來實現通訊的,那麼如何傳送、接收資訊才是根本。 socket.io中,emit函式用於傳送資料,還上述講解中,我們使用send的方式實現了資訊的互發,其實send函式只是emit的封裝,實際上還是使用了emit,且看send函式是如何實現的: function send(){ var args = toArray(arguments); args.unshift('message'); this.emit.apply(this, args); returnthis; } 在send函式中,獲取到原來的引數,並在原來的基礎上插入了一個引數message,然後呼叫了emit函式。通過send函式的實現,我們也學會了emit函式的用法,它有兩個引數,第一個引數是事件名稱,在接收端註冊該事件就可以接收到傳送過去的資訊,事件名稱可以自由定義,在不同的場景下,我們可以定義不同的事件來接收訊息。第二個引數才是傳送的資料。瞭解清楚了工作原理,下面來將send替換成emit函式傳送資訊: //app.js io.on('connection',function(socket){ socket.emit('message','連線成功!'); socket.on('message',function(data){ }); }); 服務端事件 事件監聽是實現通訊的基礎。在一些關鍵的的狀態下,socket.io可以註冊相應的事件,通過事件監聽,我們可以在這些事件中作出反應,常用的事件如下:
connection 客戶端成功連線到伺服器。
message 捕獲客戶端send資訊。
disconnect 客戶端斷開連線。
error 發生錯誤。
客戶端事件 較服務端而言,客戶端提供更多的監聽事件,在實時應用中,我們可以為這些事件註冊監聽並作出反應。
connect 成功連線到伺服器。
connecting 正在連線。
disconnect 斷開連線。
connect_failed 連線失敗。
error 連線錯誤。
message 監聽服務端send的資訊。
reconnect_failed 重新連線失敗。
reconnect 重新連線成功。
reconnecting 正在重連。
那麼客戶端socket發起連線時的順序是怎麼樣的呢?當第一次連線時,事件觸發順序為: connecting → connect 當失去連線時,事件觸發順序為:disconnect → reconnecting →connecting → reconnect → connect 名稱空間 名稱空間著實是一個非常實用好用的功能。我們可以通過名稱空間,劃分出不同的房間,在房間裡的廣播和通訊都不會影響到房間以外的客戶端。 在服務端,通過of("")的方式來劃分新的名稱空間: io.of('chat').on('connection',function(socket){ }); 示例中,我們建立一個名為chat的房間,客戶端可以通過如下方式連線到指定的房間: var socket = io.connect('/chat'); 雖然連線到指定的房間,但是我們也可以在服務端操作,自由的進出房間: socket.join('chat');//進入chat房間 socket.leave('chat');//離開chat房間 廣播訊息 在實時應用中,廣播是一個不可或缺的功能,socket.io提供兩種服務端廣播方式。 第一種廣播方式可以稱之為'全域性廣播',顧名思義,全域性廣播就是所有連線到伺服器的客戶端都會受到廣播的資訊: socket.broadcast.emit('DATA',data); 但是,在實際應用場景中,我們很多時候並不需要所有使用者都收到廣播資訊,有的廣播資訊只發送給一部分客戶端,比如某個房間裡面的使用者,那麼可以使用如下方式: socket.broadcast.to('chat').emit('DATA',data); 當使用to()的方式廣播資訊時,只有該名稱空間下的客戶端才會收到廣播資訊,是不是很方便呢。 傳遞引數 在很多應用場景中,客戶端發起連線請求時都需要傳遞引數,這些引數可能是身份驗證、初始化設定等等,那麼socket.io發起連線時如何傳遞引數呢? var socket = io.connect('/'); 由於connect函式發起連線的引數是一個url,你可能會想到把引數拼接到url上,如http://xxxx?xx=xxxx,但是很遺憾這樣是行不通的,我們可以通過這樣的方式來傳遞引數: var socket = io.connect('/',{ _query:'sid=123456'}); 在服務端可以這樣獲取到傳遞的引數: io.use(function(socket){ var query = socket.request._query; var sid = query.sid; }); 客戶端傳遞的引數已經被解析成了一個json物件,這個物件就是_query