vue中使用websocket/vue-socket.io/socket.io-client

前言

由於項目須要在vue用到websocket因此找了不少帖子與資料,可是原生的須要封裝邏輯比較複雜,對於僅僅是使用學習成本比較大,第三方插件的話我找的有vue-socket.io、socket.io、socket.io-client,其中vue-socket.io與socket.io我使用時都遇到個問題,就是全局組件掛載後沒有找到io實例,找到了io實例與相關方法可是卻沒法使用,例如on方法,使用時無任何報錯,可是控制檯沒打印後臺傳輸的數據,而最後找到了socket.io-client直接掛載io實例使用相關方法先後臺傳輸沒問題。但願有大神看到這個帖子能出個詳細的vue-socket.io正確使用教程指教下。javascript

Socket.io

Browser和WebServer間的實時數據傳輸是一個很重要的需求,但最先只能經過AJAX輪詢方式實現。在WebSocket標準沒有推出以前,AJAX輪詢是一種可行的方案。html

AJAX輪詢原理是設置定時器,定時經過AJAX同步服務端數據。這種方式存在延時且對服務端形成很大負載。直至2011年,IETF才標準化WebSocket - 一種基於TCP套接字進行收發數據的協議。前端

Socket.io將數據傳輸部分獨立出來造成engine.io,engine.io對WebSocket和AJAX輪詢進行了封裝,造成了一套API,屏蔽了細節差別和兼容性問題,實現了跨瀏覽器/跨設備進行雙向數據通訊。vue

websocket協議

WebSocket是HTML5新增的一種通訊協議,其特色是服務端能夠主動向客戶端推送信息,客戶端也能夠主動向服務端發送信息,是真正的雙向平等對話,屬於服務器推送技術的一種。java

在WebSocket API中,瀏覽器和服務器只須要作一個握手的動做,而後瀏覽器和服務端之間就造成了一條快速通道,二者之間就直接能夠數據相互傳送,帶來的好處是git

  1. 相互溝通的Header很小,大概只有2Bytes。
  2. 服務器再也不被動的接收到瀏覽器的請求以後才返回數據,而是在有新數據時就主動推送給瀏覽器。

爲了創建一個WebSocket鏈接,瀏覽器首先要向服務器發起一個HTTP請求,這個請求和一般的HTTP請求不一樣,包含了一些附加頭信息,其中附加頭信息Upgrade: WebSocket代表這是一個申請協議升級的HTTP請求。服務端解析這些頭信息,而後產生應答信息返回給客戶端,客戶端和服務端的WebSocket鏈接就創建起來了。雙方就能夠經過這個鏈接通道自由的傳遞信息,而且這個鏈接會持續直到客戶端或者服務端的某一方主動關閉鏈接web

爲何要用websocket

Browser已經支持HTTP協議,爲何還要開發一種新的WebSocket協議呢?express

咱們知道HTTP協議是一種單向的網絡協議,在創建鏈接後,僅容許Browser/UserAgent向WebServer發出請求資源後,WebServer才能返回對應的數據,而WebServer不能主動的推送數據給Browser/UserAgent。npm

最初這麼設計HTTP協議的緣由是,假設WebServer能主動的推送數據給Browser/UserAgent,那麼Browser/UserAgent就太容易受到攻擊了,一些廣告商也會主動把廣告在不經意間強行的傳輸給客戶端,這不能不說是一個災難。那麼單向的HTTP協議給Web應用開發帶哪些問題呢?後端

如今假設咱們要開發一個基於Web的應用去獲取當前WebServer的實時數據。例如股票實時行情、火車票剩餘票數等。這就須要Browser/UserAgent與WebServer之間反覆進行HTTP通訊,Browser/UserAgent不斷的發送請求去獲取當前的實時數據。

常見的方式

  • polling

Polling輪詢是經過Browser/UserAgent定時向WebServer發送HTTP請求,WebServer收到請求後把最新的數據發回給Browser/UserAgent,Browser/UserAgent獲得數據後將其顯示,而後再按期重複此過程。

雖然這樣能夠知足需求,但仍存在問題,例如某段時間內WebServer沒有更新的數據,但Browser/UserAgent仍然會定時發送請求過來詢問,WebServer能夠把之前的老數據再傳送過去,Browser/UserAgent把這些沒有變化的數據再顯示出來。這樣既浪費網絡帶寬,有浪費CPU利用率。

若是說把Browser/UserAgent發送請求的週期調大一些,就能夠緩解這個問題,但若是WebServer的數據更新很快時,這樣又不能保證Web應用獲取數據的實時性。

  • LongPolling

LongPolling是對Polling的一種改進。

Browser/UserAgent發送HTTP請求到WebServer,此時WebServer能夠作2件事情:

  1. 若是WebServer有新的數據須要傳送,就當即把數據發回給Browser/UserAgent,Browser/UserAgent收到數據後,當即再發送HTTP請求給WebServer。
  2. 若是WebServer沒有新數據須要傳送,這裏與Polling的方式不一樣的是,WebServer不是當即發送迴應給Browser/UserAgent,而是將這個請求保持住,等待有新的數據來到,再去響應這個請求。固然,若是WebServer的數據長期沒有更新,一段時間後,這個HTTP請求就會超時,Browser/UserAgent收到超時信息後,在當即發送一個新的HTTP請求給服務器,而後依次循環這個過程。

LongPolling的方式雖然在某種程度上減小了網絡帶寬和CPU利用率等問題,但仍存在缺陷

例如WebServer的數據更新速度較快,WebServer在傳送一個數據包給Browser/UserAgent後必須等待Browser的下一個HTTP請求到來,才能傳遞第二個更新的數據包給Browser。這樣的話,Browser顯示實時數據最快的時間爲2 xRTT(往返時間)。另外在網絡擁堵的狀況下,這個應該是不能讓用戶接受的。另外,因爲HTTP數據包的頭部數據量很大(一般有400多個字節),但真正被服務器須要的數據卻不多(有時只有10個字節左右),這樣的數據包在網絡上週期性傳輸,不免對網絡帶寬是一種浪費。

綜上所述,要是在Browser有一種新的網路一些,能支持客戶端和服務端的雙向通訊,並且協議的頭部又不那麼龐大就very nice了。WebSocket正是肩負這樣的使命登上了Web的舞臺。

WebSocket 原理

WebSocket是一種雙向通訊協議,它創建在TCP之上,同HTTP同樣經過TCP來傳輸數據,但與HTTP最大不一樣的是:

  1. WebSocket是一種雙向通訊協議,在創建鏈接後,WebSocket服務器和Browser/UserAgent都能主動的向對象發送或接收數據,就像Socket同樣,不一樣的是WebSocket是一種創建在Web基礎上的簡單模擬Socket的協議。
  2. WebSocket須要經過握手鍊接,相似TCP也須要客戶端和服務端進行握手鍊接,鏈接成功後才能相互通訊。

img

簡單說明下WebSocket握手的過程

當Web應用端調用new WebSocket(url)接口時,Browser就開始了與地址爲URL的WebServer創建握手鍊接的過程。

  1. Browser與WebSocket服務器經過TCP三次握手創建鏈接,若是這個創建鏈接失敗,那麼後面的過程就不會執行,Web應用將收到錯誤消息通知。
  2. 在TCP創建鏈接成功後,Browser/UserAgent經過HTTP協議傳送WebSocket支持的版本號、協議的字版本號、原始地址、主機地址等一系列字段給服務端。
  3. WebSocket服務器收到Browser/UserAgent發送來的握手請求後,若是數據包數據和格式正確,客戶端和服務端的協議版本匹配等,就接受本次握手鍊接,並給出對應的數據回覆,一樣回覆的數據包也是採用HTTP協議傳輸。
  4. Browser收到服務器回覆的數據包後,若是數據包內容、格式都沒有問題的話,就表示本次鏈接成功,觸發onopen消息,此時Web開發者就能夠在此時經過send接口向服務器發送數據。不然,握手鍊接失敗,Web應用會收到onerror消息,而且能知道鏈接失敗的緣由。

WebSocket與TCP、HTTP的關係

WebSocket與HTTP協議同樣都是基於TCP的,因此它們都是可靠的協議,Web開發者調用的WebSocketsend函數在Browser的實現中最終都是經過TCP的系統接口進行傳輸的。

WebSocket和HTTP協議樣都屬於應用層協議,那麼它們之間有沒有什麼關係呢?

答案是確定的,WebSocket在創建握手鍊接時,數據是經過HTTP協議傳輸的。但在創建鏈接以後,真正的數據傳輸階段是不須要HTTP參與的。

img

WebSocket Server

若是要搭建一個WebServer,咱們會有不少選擇,市場上也有不少成熟的產品供咱們是使用。例如開源的Apache,安裝配置後便可工做。但若是想要搭建一個WebSocket服務器就沒有那麼輕鬆,由於WebSocket是一種新的通訊協議,目前仍是草案,沒有成爲標準,市場上也沒有成熟的WebSocket服務器或Library實現WebSocket協議,咱們必須本身手動編碼去解析和組裝WebSocket的數據包。要完成一個WebSocket服務器,估計全部的人都想放棄,不過市場上有幾款比較好的開源Library可供使用。例如PyWebSocket、WebSocket-Node、LibWebSockets等,這些Library已經實現了WebSocket數據包的封裝和解析,咱們能夠調用這些接口,這在很大程度上減小了咱們的工做量

socket.io-client

官方npm文檔

使用方法,經過npm包導入import socket.io-client,經過src方式導入<script src="/socket.io/socket.io.js"></script>

前端代碼

// 導入依賴
import io from 'socket.io-client';

export default {
data() {
return {
user: '',
message: '',
messages: [],
socket : io('localhost:3001') // 掛載依賴
}
},
methods: {
sendMessage(e) {
e.preventDefault();
},
created(){
// 發送數據給後端
this.socket.emit('send message',{
msg: 'front end send message'
})
// 監聽後端傳過來的數據
this.socket.on('message',(data)=>{
console.log(data)
})
}
},

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
/**
一、Express初始化app爲能夠提供給HTTP服務器的函數處理程序(如第2行所示)。
二、咱們定義了一個路由處理程序/,當咱們訪問咱們的網站主頁時會被調用。
三、咱們使http服務器在端口3000上偵聽
**/
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});

// on事件接收信息,這裏接收鏈接事件
io.on('connection', (socket) => {
console.log('a user connected');
// 監聽前端send message事件,這個名字是自定義的,可是先後端的監聽與接受要統一且惟一
io.on('send message',(data)=>{
console.log(data)
// 經過message事件給前端發送數據
socket.emit('message', {
msg: `new message`,
});
})
});

http.listen(3000, () => {
console.log('listening on *:3000');
});

vue-socket.io使用問題

vue中原生websocket的使用

原生websocket封裝

js原生websocket封裝(轉載)

個人理解是由於socket.io使用的時候掛載連接時是經過socket.io-client依賴掛載的,而使用這些方法是須要經過socket.io-client建立io實例,因此socket.io的官網能夠查看到相關的方法socket.io-client可使用

socket.io中文網

socket.io官網

若是想了解更多的方法能夠到socket.io官網查看

從這兩段代碼能夠看出,在socket.io-client中on表明監聽事件, emit表明發送事件,而事件名是自定義的,先後端對此的定義應該一致且惟一。

Node.js服務端代碼

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
/**
一、Express初始化app爲能夠提供給HTTP服務器的函數處理程序(如第2行所示)。
二、咱們定義了一個路由處理程序/,當咱們訪問咱們的網站主頁時會被調用。
三、咱們使http服務器在端口3000上偵聽
**/
app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

// on事件接收信息,這裏接收鏈接事件
io.on('connection', (socket) => {
  console.log('a user connected');
  // 監聽前端send message事件,這個名字是自定義的,可是先後端的監聽與接受要統一且惟一
    io.on('send message',(data)=>{
    console.log(data)
    // 經過message事件給前端發送數據
      socket.emit('message', {
        msg: `new message`,
      });
  })
});

http.listen(3000, () => {
  console.log('listening on *:3000');
});

從這兩段代碼能夠看出,在socket.io-client中on表明監聽事件, emit表明發送事件,而事件名是自定義的,先後端對此的定義應該一致且惟一。

js原生websocket封裝(轉載)

原生websocket封裝

vue中原生websocket的使用

vue-socket.io使用問題
阮一峯websocket教程

相關文章
相關標籤/搜索