Socket.IO用於瀏覽器與node.js之間實現實時通信。Socket.IO設計的目標是支持任何的瀏覽器,任何Mobile設備。支持主流的PC瀏覽器 (IE,Safari,Chrome,Firefox,Opera等),Mobile瀏覽器(iphone Safari/ipad Safari/android WebKit/WebOS WebKit等)。
Socket.IO支持如下方式的通信方式,根據瀏覽器的支持程度,自動選擇使用哪種技術進行通信:
- WebSocket
- Flash Socket
- AJAX long-polling
- AJAX multipart streaming
- Forever IFrame
- JSONP polling
Socket.IO解決了實時的通信問題,並統一了服務端與客戶端的編程方式。啓動了socket以後,就像建立了一條客戶端與服務端的管道,兩邊可以互通有無。
關於engine.io
engine.io是一個Socket.IO的抽象實現,作爲Socket.IO的服務器和瀏覽器之間交換的數據的傳輸層。它不會取代Socket.IO,它只是抽象出固有的複雜性,支持多種瀏覽器,設備和網絡的實時數據交換。
Socket.IO的基本使用方式
建立服務器
例:創建io服務器的兩種簡單的方法。
var io = require('Socket.IO')(); // 或 var Server = require('Socket.IO'); var io = new Server();
服務器配置
Socket.IO服務器的配置項與engine.io相同。
- pingTimeout (Number):等待響應包的時間,單位爲毫秒。默認爲60000。
- pingInterval (Number):設定每隔在一定時間發送一個ping包,可以用於心跳包的設置。默認爲25000。
- maxHttpBufferSize (Number):消息最大大小,可用於避免DoS攻擊。默認爲 10E7。
- allowRequest (Function):該配置項爲一個函數。第一個參數是一個一個握手或連接請求。第二個參數是一個回調函數function(err,success),success是boolean值,false表示連接失敗;err是錯誤碼。該函數可以用於決定是否繼續。
- transports (<Array> String):指定傳輸的連接方式。默認爲['polling', 'websocket']。
- allowUpgrades (Boolean):是否允許升級傳輸協議。 默認爲true。
- cookie (String|Boolean):HTTP Cookie的名字。默認爲io。
通過Node http server使用Socket.IO
// Server (app.js) var app = require('http').createServer(handler) var io = require('Socket.IO')(app); var fs = require('fs'); app.listen(80);
function handler (req, res) { fs.readFile(__dirname + '/index.html', function (err, data) { if (err) { res.writeHead(500); return res.end('Error loading index.html'); }
res.writeHead(200); res.end(data); }); } io.on('connection', function (socket) { socket.emit('news', { hello: 'world' }); socket.on('my other event', function (data) { console.log(data); }); }); // Client (index.html) <script src="/Socket.IO/Socket.IO.js"></script> <script> var socket = io('http://localhost'); socket.on('news', function (data) { console.log(data); socket.emit('my other event', { my: 'data' }); }); </script>
通過Express 3/4 使用Socket.IO
// Server (app.js) var app = require('express')(); var server = require('http').Server(app); var io = require('Socket.IO')(server); server.listen(80); app.get('/', function (req, res) { res.sendfile(__dirname + '/index.html'); }); io.on('connection', function (socket) { socket.emit('news', { hello: 'world' }); socket.on('my other event', function (data) { console.log(data); }); }); // Client (index.html) <script src="/Socket.IO/Socket.IO.js"></script> <script> var socket = io.connect('http://localhost'); socket.on('news', function (data) { console.log(data); socket.emit('my other event', { my: 'data' }); }); </script>
發送以及接收事件
Socket.IO 提供了默認事件(如:connect, message, disconnect)。另外,Socket.IO允許發送並接收自定義事件。
事件的發送:
//發送給對應的客戶端 socket.emit('message',"this is a test"); //發送給所有客戶端 io.sockets.emit('message',"this is a test"); //發送消息給指定socketId的客戶端。 io.sockets.socket(socketid).emit('message','for your eyes only'); //發送自定義的事件 socket.emit("my-event","this is a test");
事件的接收:
socket.on("event name",function(data){ //data爲接收到的數據。 });
示例代碼
例1:
// note, io.listen(<port>) will create a http server for you var io = require('Socket.IO').listen(80); io.sockets.on('connection', function (socket) { io.sockets.emit('this', { will: 'be received by everyone'}); socket.on('private message', function (from, msg) { console.log('I received a private message by ', from, ' saying ', msg); }); socket.on('disconnect', function () { io.sockets.emit('user disconnected'); }); });
例2:
// Server (app.js) var io = require('Socket.IO').listen(80); io.sockets.on('connection', function (socket) { socket.on('ferret', function (name, fn) { fn('woot'); }); }); // Client (index.html) <script> var socket = io(); // TIP: io() with no args does auto-discovery socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too! socket.emit('ferret', 'tobi', function (data) { console.log(data); // data will be 'woot' }); }); </script>
廣播消息
廣播消息由服務器發送,會發送給除了當前連接的其他所有客戶端。
//發送給除了發送者之外的所有客戶端。 socket.broadcast.emit('message',"this is a test");
例:廣播用戶連接的自定義事件。
var io = require('Socket.IO').listen(80);
io.sockets.on('connection', function (socket) { socket.broadcast.emit('user connected'); });
發送易變(volatile)的數據
volatile 意思大概是說,當服務器發送數據時,客戶端因爲各種原因不能正常接收,比如網絡問題、或者正處於長連接的建立連接階段。此時會讓我們的應用變得 suffer,那就需要考慮發送 volatile 數據。
var io = require('Socket.IO').listen(80); io.sockets.on('connection', function (socket) { var tweets = setInterval(function () { getBieberTweet(function (tweet) { socket.volatile.emit('bieber tweet', tweet); }); }, 100); socket.on('disconnect', function () { clearInterval(tweets); }); });
即使客戶端沒連線,一樣可以這樣發送,服務器會自動丟棄發送失敗的數據。
命名空間
通過命名空間可以爲Socket.IO設置子程序。默認命名空間爲“/”,Socket.IO默認連接該路徑。
使用of()函數可以自定義命名空間。
// Server (app.js) var io = require('Socket.IO').listen(80); var chat = io .of('/chat') .on('connection', function (socket) { socket.emit('a message', { that: 'only' , '/chat': 'will get' }); chat.emit('a message', { everyone: 'in' , '/chat': 'will get' }); }); var news = io .of('/news') .on('connection', function (socket) { socket.emit('item', { news: 'item' }); }); // Client (index.html) <script> var chat = io.connect('http://localhost/chat') , news = io.connect('http://localhost/news'); chat.on('connect', function () { chat.emit('hi!'); }); news.on('news', function () { news.emit('woot'); }); </script>
房間
房間是Socket.IO提供的一個非常好用的功能。房間相當於爲指定的一些客戶端提供了一個命名空間,所有在房間裏的廣播和通信都不會影響到房間以外的客戶端。
進入房間與離開房間
使用join()方法將socket加入房間:
io.on('connection', function(socket){ socket.join('some room'); });
使用leave()方法離開房間:
socket.leave('some room');
在房間中發送消息
在某個房間中發送消息:
io.to('some room').emit('some event');
to()方法用於在指定的房間中,對除了當前socket的其他socket發送消息。
socket.broadcast.to('game').emit('message','nice game');
in()方法用於在指定的房間中,爲房間中的所有有socket發送消息。
io.sockets.in('game').emit('message','cool game');
當socket進入一個房間之後,可以通過以下兩種方式在房間裏廣播消息:
//向my room廣播一個事件,提交者會被排除在外(即不會收到消息) io.sockets.on('connection', function (socket) { //注意:和下面對比,這裏是從客戶端的角度來提交事件 socket.broadcast.to('my room').emit('event_name', data); } //向another room廣播一個事件,在此房間所有客戶端都會收到消息 //注意:和上面對比,這裏是從服務器的角度來提交事件 io.sockets.in('another room').emit('event_name', data); //向所有客戶端廣播 io.sockets.emit('event_name', data);
除了向房間廣播消息之外,還可以通過以下API來獲取房間的信息。
//獲取所有房間的信息 //key爲房間名,value爲房間名對應的socket ID數組 io.sockets.manager.rooms //獲取particular room中的客戶端,返回所有在此房間的socket實例 io.sockets.clients('particular room') //通過socket.id來獲取此socket進入的房間信息 io.sockets.manager.roomClients[socket.id]