首頁 > web前端 > js教程 > 主體

node.js中socket.io學習教學介紹(三)

零下一度
發布: 2017-05-03 10:02:19
原創
1146 人瀏覽過

這篇文章更加深入的給大家介紹了socket.io的相關資料,之前已經介紹了socket.io的基本教程和應用,本文更為深入的來介紹下socket.io的使用,需要的朋友可以參考借鑒,下面來一起看看吧。

前言

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() }) })<br/>

與allowRequest對比

allowRequest可以進行一些校驗,提取,為什麼還要需要中間件?

  • allowRequest傳入的http.request實例,而中間件出入資料socket實例,socket實例包含request實例,且有更多資訊

  • #中間件直接支援多個非同步流程巢狀,而allowRequest需要自己實作


#與connection事件對比

#connection事件也傳入socket,也可以進行數驗,提取,為什麼還要需要中間件?

  • 中間件直接支援多個非同步流程嵌套,而allowRequest需要自己實作

  • 中间件成功后到connection事件发送成功前,socket.io还做了一些工作,比如把socket实例添加到connected对象中,加入聊天室等。如果因为权限中断连接,在中间件中处理更省资源.

聊天室

聊天室是对当前连接的socket集合根据特定规则进行归组,方便群发消息。可以类比QQ群的概率.

socket.join(&#39;room name&#39;) //进入 
socket.leave(&#39;room name&#39;) //退出
登入後複製
io.to(&#39;some room&#39;).emit(&#39;some event&#39;) // io.to与io.in同义,向某个聊天室的所有成员发送消息
登入後複製

默认聊天室

每个socket在连接成功后会自动创建一个默认个聊天室,这个聊天室的名字是当前socket的id,可以通过默认聊天室实现向特定用户发送消息

socket.on(&#39;say to someone&#39;, (id, msg) => { 
 socket.broadcast.to(id).emit(&#39;my message&#39;, msg)
})
登入後複製

消息发送

应答消息

普通消息不需要回应,而应答消息提供了应答机制

io.on(&#39;connection&#39;, socket => { 
 socket.emit(&#39;an event&#39;, { some: &#39;data&#39; }) //普通消息

 socket.emit(&#39;ferret&#39;, &#39;tobi&#39;, function (data) { //应答消息
 console.log(data); // data will be &#39;woot&#39;
 })
})
登入後複製


socket.on(&#39;ferret&#39;, (name, fn) => { 
 fn(&#39;woot&#39;)
})
登入後複製

压缩

socket.compress(true)启用压缩,调用后当前连接的所有数据在传递给客户端前都会进行压缩

volatile标志

socket.io在正常情况下对发送的消息进行追踪,确保消息发送成功,而设置volatile后发送消息,socket.io不会对消息追踪,消息可能丢失

分类

// 客户端发送消息
socket.emit(&#39;hello&#39;, &#39;can you hear me?&#39;, 1, 2, &#39;abc&#39;);

// 向所有连接的客户端(除了自己)发送消息
socket.broadcast.emit(&#39;broadcast&#39;, &#39;hello friends!&#39;);

// 向game聊天室发送消息,自己不算
socket.to(&#39;game&#39;).emit(&#39;nice game&#39;, "let&#39;s play a game");

// 同时向game1和game2聊天室发送消息,自己不算
socket.to(&#39;game1&#39;).to(&#39;game2&#39;).emit(&#39;nice game&#39;, "let&#39;s play a game (too)");

// 向game聊天室的所有人发送消息
io.in(&#39;game&#39;).emit(&#39;big-announcement&#39;, &#39;the game will start soon&#39;);

// 发送消息到<socketid>客户端
socket.to(<socketid>).emit(&#39;hey&#39;, &#39;I just met you&#39;);
// 发送应答消息
socket.emit(&#39;question&#39;, &#39;do you think so?&#39;, function (answer) {});
登入後複製

以上是node.js中socket.io學習教學介紹(三)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板