socket.io學習教程之深入學習篇(三),socket.io深入學習

來源:互聯網
上載者:User

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

與allowRequest對比

allowRequest可以進行一些校正,提取,為什麼還要需要中介軟體?

  • allowRequest傳入的http.request執行個體,而中介軟體出入資料socket執行個體,socket執行個體包含request執行個體,且有更多資訊
  • 中介軟體直接支援多個非同步流程嵌套,而allowRequest需要自己實現

與connection事件對比

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

  • 中介軟體直接支援多個非同步流程嵌套,而allowRequest需要自己實現
  • 中介軟體成功後到connection事件發送成功前,socket.io還做了一些工作,比如把socket執行個體添加到connected對象中,加入聊天室等。如果因為許可權中斷串連,在中介軟體中處理更省資源.

聊天室

聊天室是對當前串連的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) {}); 

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的協助,如果有疑問大家可以留言交流,謝謝大家對幫客之家的支援。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.