實時通訊之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文件:
<script src="/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);
return this;
}
在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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章