您好,登錄后才能下訂單哦!
前言
socket.io提供了基于事件的實時雙向通訊,本文深入的介紹了socket.io,下面來看看詳細的內容吧。
靜態文件
socket.io默認情況下會通過socket.io-client包提供socket.io.min.js和socket.io.js.map下載
運行實例app.js
let app = require('http').createServer() let io = require('socket.io')(app) app.listen(3000);
瀏覽器訪問http://localhost:3000/socket.io/socket.io.js可以加載壓縮的源碼,訪問http://localhost:3000/socket.io/socket.io.js.map加載sourcemap
我們可以改變這種行為
禁用socket.io.js下載
方法1: 實例化時傳入控制參數serveClient值false
let io = require('socket.io')(app, { serveClient: false })
方法2: 調用函數serverClient
let app = require('http').createServer() let io = require('socket.io')() io.serveClient(false) io.listen(app) // 或者io.attach(app)
如果在調用函數前服務已綁定http.Server
,該方法將不起作用
禁用后再次訪問將提示{"code":0,"message":"Transport unknown"}
修改靜態文件路徑
socket.io.js路徑可以改變,其默認路徑為/socket.io。
實例化時傳參
let io = require('socket.io')(app, { path: '/io' })
調用函數path
let app = require('http').createServer() let io = require('socket.io')() io.path('/io') io.listen(app)
如果在調用函數前服務已綁定http.Server
,該方法將不起作用
安全策略
socket.io提供了兩種安全策略
allowRequest
函數allowRequest有兩個參數,第一個參數為收到的握手包(http.request
)對象,作為判斷依據, success), err是錯誤對象,success為boolean, false表示阻止建立連接
前端請求帶上token
let socket = io('http://localhost:3000?token=abc') socket.on('connect', () => { console.log('connect') }) socket.on('connect_error', err => { socket.disconnect() console.log('connect_error', err) })
后端allowRequest根據token判斷是否繼續
let app = require('http').createServer() let io = require('socket.io')(app, { allowRequest: (req, cb) => { if (req._query && req._query.token === 'abc') return cb(null, true) cb(null, false) } });
origins
可以對源進行限制
1、實例化時限制源
let app = require('http').createServer() let io = require('socket.io')(app, { origins: 'http://localhost:3000' })
2、origins函數設置源
origins函數有兩種形式
origins(string)
: 設置運行的源
origins(string, fn(err, success))
: 通過函數判斷源是否允許
io.origins('http://localhost:*') io.origins((origin, cb) => { if (origin === 'http://localhost:3000/') return cb(null, true) cb(null, false) })
名稱空間
名稱空間用來對服務端/客戶端的連接隔離,有些地方,也稱呼名稱空間(namespace)為通道(channel)。下面舉例對其意義進行說明
我們需要實現一個協同應用,這個應用有兩個功能:
用socket.io實現這個應用,有如下幾種形式
1、完全獨立: 協同編輯有一個獨立服務edit.socket.test
,消息系統一個獨立服務message.socket.test
let editSocket = io('edit.socket.test') let messageSocket = io('message.socket.test')
2、名稱空間: 只運行一個獨立服務,通過名稱空間進行隔離
let app = require('http').createServer() let io = require('socket.io')(app) let editServer = io.of('/edit') let messsageServer = io.of('/message') editServer.on('connection', socket => { //編輯相關 }) messsageServer.on('connection', socket => { /消息相關 })
let editSocket = io('socket.test/edit') let messageSocket = io('socket.test/message')
3、事件名約定: 通過為事件名添加進行隔離
let app = require('http').createServer() let io = require('socket.io')(app) io.on('connection', socket => { //編輯相關 io.emit('edit:test') io.on('edit:test', data => { }) //消息相關 io.emit('message:test') io.on('message:test', data => { }) }
通過事件名約定程序的侵入性太大,不利于拆分和重組,不推薦。 而完全獨立的模式需要使用兩個socket連接,即浪費瀏覽器允許的并發連接數,又更多消耗服務器資源。使用名稱空間即能實現很好的隔離,又不會對資源造成浪費。
默認名稱空間
socket.io實例化時自動綁定路徑為/的名稱空間
let app = require('http').createServer() let io = require('socket.io')(app) io.sockets // io.of('/').sockets io.emit // 代理io.of('/').emit, 類似函數有'to', 'in', 'use', 'send', 'write', 'clients', 'compress'
中間件
socket.io的名空間通過use注冊中間件,中間件在客戶端與服務端建立連接成功后,connet事件派發前調用一次。
利用中間件數據校驗
io.use((socket, next) => { if (socket.request.headers.cookie) return next() next(new Error('Authentication error')) })
利用中間件提取或轉換數據 io.use((socket, next) => {
getInfo(socket.request.query.id, (err, data) => { if (err) return next(err) socket.custom = data next() }) })
與allowRequest對比
allowRequest可以進行一些校驗,提取,為什么還要需要中間件?
與connection事件對比
connection事件也傳入socket,也可以進行數驗,提取,為什么還要需要中間件?
聊天室
聊天室是對當前連接的socket集合根據特定規則進行歸組,方便群發消息。可以類比QQ群的概率.
socket.join('room name') //進入 socket.leave('room name') //退出
io.to('some room').emit('some event') // io.to與io.in同義,向某個聊天室的所有成員發送消息
默認聊天室
每個socket在連接成功后會自動創建一個默認個聊天室,這個聊天室的名字是當前socket的id,可以通過默認聊天室實現向特定用戶發送消息
socket.on('say to someone', (id, msg) => { socket.broadcast.to(id).emit('my message', msg) })
消息發送
應答消息
普通消息不需要回應,而應答消息提供了應答機制
io.on('connection', socket => { socket.emit('an event', { some: 'data' }) //普通消息 socket.emit('ferret', 'tobi', function (data) { //應答消息 console.log(data); // data will be 'woot' }) })
socket.on('ferret', (name, fn) => { fn('woot') })
壓縮
socket.compress(true)
啟用壓縮,調用后當前連接的所有數據在傳遞給客戶端前都會進行壓縮
volatile標志
socket.io在正常情況下對發送的消息進行追蹤,確保消息發送成功,而設置volatile后發送消息,socket.io不會對消息追蹤,消息可能丟失
分類
// 客戶端發送消息 socket.emit('hello', 'can you hear me?', 1, 2, 'abc'); // 向所有連接的客戶端(除了自己)發送消息 socket.broadcast.emit('broadcast', 'hello friends!'); // 向game聊天室發送消息,自己不算 socket.to('game').emit('nice game', "let's play a game"); // 同時向game1和game2聊天室發送消息,自己不算 socket.to('game1').to('game2').emit('nice game', "let's play a game (too)"); // 向game聊天室的所有人發送消息 io.in('game').emit('big-announcement', 'the game will start soon'); // 發送消息到<socketid>客戶端 socket.to(<socketid>).emit('hey', 'I just met you'); // 發送應答消息 socket.emit('question', 'do you think so?', function (answer) {});
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。