由於項目須要在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
Browser和WebServer間的實時數據傳輸是一個很重要的需求,但最先只能經過AJAX輪詢方式實現。在WebSocket標準沒有推出以前,AJAX輪詢是一種可行的方案。html
AJAX輪詢原理是設置定時器,定時經過AJAX同步服務端數據。這種方式存在延時且對服務端形成很大負載。直至2011年,IETF才標準化WebSocket - 一種基於TCP套接字進行收發數據的協議。前端
Socket.io將數據傳輸部分獨立出來造成engine.io,engine.io對WebSocket和AJAX輪詢進行了封裝,造成了一套API,屏蔽了細節差別和兼容性問題,實現了跨瀏覽器/跨設備進行雙向數據通訊。vue
WebSocket是HTML5新增的一種通訊協議,其特色是服務端能夠主動向客戶端推送信息,客戶端也能夠主動向服務端發送信息,是真正的雙向平等對話,屬於服務器推送技術的一種。java
在WebSocket API中,瀏覽器和服務器只須要作一個握手的動做,而後瀏覽器和服務端之間就造成了一條快速通道,二者之間就直接能夠數據相互傳送,帶來的好處是git
Header
很小,大概只有2Bytes。爲了創建一個WebSocket鏈接,瀏覽器首先要向服務器發起一個HTTP請求,這個請求和一般的HTTP請求不一樣,包含了一些附加頭信息,其中附加頭信息Upgrade: WebSocket
代表這是一個申請協議升級的HTTP請求。服務端解析這些頭信息,而後產生應答信息返回給客戶端,客戶端和服務端的WebSocket鏈接就創建起來了。雙方就能夠經過這個鏈接通道自由的傳遞信息,而且這個鏈接會持續直到客戶端或者服務端的某一方主動關閉鏈接web
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輪詢是經過Browser/UserAgent定時向WebServer發送HTTP請求,WebServer收到請求後把最新的數據發回給Browser/UserAgent,Browser/UserAgent獲得數據後將其顯示,而後再按期重複此過程。
雖然這樣能夠知足需求,但仍存在問題,例如某段時間內WebServer沒有更新的數據,但Browser/UserAgent仍然會定時發送請求過來詢問,WebServer能夠把之前的老數據再傳送過去,Browser/UserAgent把這些沒有變化的數據再顯示出來。這樣既浪費網絡帶寬,有浪費CPU利用率。
若是說把Browser/UserAgent發送請求的週期調大一些,就能夠緩解這個問題,但若是WebServer的數據更新很快時,這樣又不能保證Web應用獲取數據的實時性。
LongPolling是對Polling的一種改進。
Browser/UserAgent發送HTTP請求到WebServer,此時WebServer能夠作2件事情:
LongPolling的方式雖然在某種程度上減小了網絡帶寬和CPU利用率等問題,但仍存在缺陷。
例如WebServer的數據更新速度較快,WebServer在傳送一個數據包給Browser/UserAgent後必須等待Browser的下一個HTTP請求到來,才能傳遞第二個更新的數據包給Browser。這樣的話,Browser顯示實時數據最快的時間爲2 xRTT(往返時間)。另外在網絡擁堵的狀況下,這個應該是不能讓用戶接受的。另外,因爲HTTP數據包的頭部數據量很大(一般有400多個字節),但真正被服務器須要的數據卻不多(有時只有10個字節左右),這樣的數據包在網絡上週期性傳輸,不免對網絡帶寬是一種浪費。
綜上所述,要是在Browser有一種新的網路一些,能支持客戶端和服務端的雙向通訊,並且協議的頭部又不那麼龐大就very nice了。WebSocket正是肩負這樣的使命登上了Web的舞臺。
WebSocket是一種雙向通訊協議,它創建在TCP之上,同HTTP同樣經過TCP來傳輸數據,但與HTTP最大不一樣的是:
簡單說明下WebSocket握手的過程
當Web應用端調用new WebSocket(url)
接口時,Browser就開始了與地址爲URL的WebServer創建握手鍊接的過程。
onopen
消息,此時Web開發者就能夠在此時經過send
接口向服務器發送數據。不然,握手鍊接失敗,Web應用會收到onerror
消息,而且能知道鏈接失敗的緣由。WebSocket與HTTP協議同樣都是基於TCP的,因此它們都是可靠的協議,Web開發者調用的WebSocket
的send
函數在Browser的實現中最終都是經過TCP的系統接口進行傳輸的。
WebSocket和HTTP協議樣都屬於應用層協議,那麼它們之間有沒有什麼關係呢?
答案是確定的,WebSocket在創建握手鍊接時,數據是經過HTTP協議傳輸的。但在創建鏈接以後,真正的數據傳輸階段是不須要HTTP參與的。
若是要搭建一個WebServer,咱們會有不少選擇,市場上也有不少成熟的產品供咱們是使用。例如開源的Apache,安裝配置後便可工做。但若是想要搭建一個WebSocket服務器就沒有那麼輕鬆,由於WebSocket是一種新的通訊協議,目前仍是草案,沒有成爲標準,市場上也沒有成熟的WebSocket服務器或Library實現WebSocket協議,咱們必須本身手動編碼去解析和組裝WebSocket的數據包。要完成一個WebSocket服務器,估計全部的人都想放棄,不過市場上有幾款比較好的開源Library可供使用。例如PyWebSocket、WebSocket-Node、LibWebSockets等,這些Library已經實現了WebSocket數據包的封裝和解析,咱們能夠調用這些接口,這在很大程度上減小了咱們的工做量
使用方法,經過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');
});
個人理解是由於socket.io使用的時候掛載連接時是經過socket.io-client
依賴掛載的,而使用這些方法是須要經過socket.io-client
建立io實例,因此socket.io的官網能夠查看到相關的方法socket.io-client
可使用
若是想了解更多的方法能夠到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
表明發送事件,而事件名是自定義的,先後端對此的定義應該一致且惟一。