三分鐘搭建websocket實時線上聊天,專案經理也不敢這麼寫

程式零世界發表於2020-06-06

我們先看一下下面這張圖:

在這裡插入圖片描述

可以看到這是一個簡易的聊天室,兩個視窗的訊息是實時傳送與接收的,這個主要就是用我們今天要講的websocket實現的。

websocket是什麼?

websocket是一種網路通訊協議,我們都知道http協議,http協議只能從客戶端主動發起,不能從服務端推送資料到客戶端,今天我們講的websocket就是一種不僅能從客戶端傳送資料到服務端,也可以主動從服務的推送資料給客戶端的一種協議。
我們先看一張圖:

在這裡插入圖片描述

我們可以看到,http請求是客戶端發起請求,服務端響應,然後斷開連線,客戶端發起,服務端響應的一種迴圈。而websocket協議是客戶端發起連線後,就會一直保持連線,期間客戶端和服務端都可以向對方傳送資料,直到連線關閉。
websocket其他的一些特點:

(1)建立在 TCP 協議之上,伺服器端的實現比較容易。

(2)與 HTTP 協議有著良好的相容性。預設埠也是80和443,並且握手階段採用 HTTP 協議,因此握手時不容易遮蔽,能通過各種 HTTP 代理伺服器。

(3)資料格式比較輕量,效能開銷小,通訊高效。

(4)可以傳送文字,也可以傳送二進位制資料。

(5)沒有同源限制,客戶端可以與任意伺服器通訊。

(6)協議識別符號是ws(如果加密,則為wss),伺服器網址就是 URL。

應用場景

試想一下這樣的場景,我們需要實現一個支付成功後,向使用者給一個成功的提示,那麼在websocket協議沒有應用之前,人們是使用一種輪詢的方式。就是客戶端定時向服務端傳送請求,看有沒有收到支付金額,沒有就一直髮送,收到了再停止。類似下面的程式碼:

function getIsPaySuccess() {
	var timmer = setInterval(function () {
		$.ajax({
			url: '/getJayStatus',
			success: function (res) {
				if (res.status) {
					clearInterval(timmer)
				}
			},
			fail: function () {

			}
		})
	}, 1000)
}

在傳送請求的工程中,浪費了大量的資源,而且響應也不是及時的,因為我是每隔1秒請求一次,並不能立刻得到支付成功的狀態。這時候我們就需要用到websocket的方式了。總體來說,websocket需要用在一些能及時響應的場景中。

1. 社交訂閱
有時候我們需要及時收到訂閱訊息,比如說開獎通知,比如說線上邀請,支付結果等。

2. 多玩家遊戲
很多遊戲都是協同作戰的,玩家的操作和狀態肯定需要及時同步到所有玩家。

3. 協同編輯文件
同一份文件,編輯狀態得同步到所有參與的使用者介面上。

4. 資料流狀態
比如說上傳下載檔案,檔案進度,檔案是否上傳成功。

5. 多人聊天
很多場景下都需要多人蔘與討論聊天,使用者傳送的訊息得第一時間同步到所有使用者。

6. 股票虛擬貨幣價格
股票和虛擬貨幣的價格都是實時波動的,價格跟使用者的操作息息相關,及時推送對使用者跟盤有很大的幫助。

程式碼實現

我們用下面一段程式碼來講解websocket的建立,擁有的屬性,能呼叫的方法和能監聽的事件:

// 連線狀態的列舉
const readyStateMap = {
	0: '連線尚未建立',
	1: '連線已建立,可以進行通訊',
	2: '連線正在進行關閉',
	3: '連線已經關閉或者連線不能開啟'
}
Object.freeze(readyStateMap)
class WsTest {
	constructor(url) {
		// 建立websocket例項,第一個引數是連線的url,沒有跨域限制,第二個引數是可接受的協議
		this.ws = new WebSocket(url);
		// readyState屬性,只讀屬性,表示連線狀態
		console.log(this.ws.readyState, readyStateMap[this.ws.readyState])
		// 只讀屬性 bufferedAmount 已被 send() 放入正在佇列中等待傳輸,但是還沒有發出的 UTF-8 文字位元組數。
		console.log(this.ws.bufferedAmount)
		this.initWs()
	}
	initWs() {
		// 事件onopen,指連線成功
		this.ws.onopen = () => {
			console.log(this.ws.readyState, readyStateMap[this.ws.readyState])
			// 方法,向服務端傳送訊息,傳輸字串
			this.ws.send(JSON.stringify({type: 'connection'}))
		};
		// 事件onmessage,指接收到服務端訊息
		this.ws.onmessage = (evt) => {
			console.log(evt.data, 'data')
			const {type, msg} = JSON.parse(evt.data);
			console.log('訊息型別:' + type, '使用者id:' + msg)
			// 方法,關閉連線
			this.ws.close()
			console.log(this.ws.readyState, readyStateMap[this.ws.readyState])
		};
		// 事件onclose,關閉連線,也可以從服務端強制斷開連線,這裡可以重新發起連線
		this.ws.onclose = () => {
			console.log(this.ws.readyState, readyStateMap[this.ws.readyState])
		};
		// 事件onerror,通訊發生錯誤時觸發
		this.ws.onerror = () => {
			console.log(this.ws.readyState, readyStateMap[this.ws.readyState])
		};
	}
}
const ws = new WsTest('ws://203.195.156.57:30002')

上面的程式碼都有註釋,應該不難看出websocket的使用方法,這段程式碼可以直接放到chrome控制檯執行:

在這裡插入圖片描述

相容性

2.png

可以看到幾乎所有瀏覽器都支援了。

總結

  1. websocket是一個類似http的一種通訊協議。
  2. websocket最大的特點是客戶端和服務端能相互給對方傳送訊息。
  3. websocket廣泛引用在需要實時通訊的一些應用上面。
  4. websocket沒有同源限制,而且效能開銷小,通訊高效。

本文主要講了websocket協議的定義和基本用法,下一期我會結合本文開始的聊天室來實現一個具體的websocket應用。

聊天室線上體驗地址:關注公眾號:程式零世界 體驗線上聊天

學習如逆水行舟,不進則退,前端技術飛速發展,如果每天不堅持學習,就會跟不上,我會陪著大家,每天堅持推送博文,跟大家一同進步,希望大家能關注我,第一時間收到最新文章。

file

相關文章