以前在項目中簡單的使用過,可是追究使用它的原因、優勢以及原理,在這以前筆者也是模糊不清,因此在這期間,作了比較系統的瞭解後,在此記錄一番。html
話很少說,切入正題。可能在瞭解到這個協議的時候,大多數人都不知道它是作什麼,或者說不知道爲何須要這個協議,那麼咱們就從基礎開始,一點點的瞭解。node
仍是如今這裏粘一個下面代碼的github地址。 git
WebSocket是一種 網絡傳輸協議(說到網絡協議,你們可能會立馬想到HTTP協議,下面會有二者的對比),可在單個TCP鏈接上進行全雙工通訊,位於OSI模型的應用層。github
WebSocket使得客戶端和服務器之間的數據交換變得更加簡單,容許服務端向客戶端推送數據。在WebSocket API中,瀏覽器和服務器只須要完成一次握手,二者之間就能夠建立持久性的連接,並進行雙向數據傳輸。web
WebSocket協議規範將 ws
(WebSocket)和 wss
(WebSocket Secure)定義爲兩個新的統一資源標識符,分別對應明文和加密鏈接。ajax
WebSocket最大特色就是,服務器能夠主動向客戶端推送信息,客戶端也能夠主動向服務器發送信息。算法
在這個協議以前,不少網站爲了實現 推送技術,所用的技術都是輪詢。輪詢是在特定的時間間隔,由瀏覽器對服務器發出HTTP請求,而後由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器須要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會消耗不少的帶寬資源。npm
在這種狀況下,HTML5定義了WebSocket協議,能更好的節省服務器資源和帶寬,而且可以更實時地進行通信。api
在上面簡單的介紹WebSocket以後,想必你們也均可以總結出一些WebSocket的優勢,下面相較於HTTP再作進一步的總結瀏覽器
較少的控制開銷:在鏈接建立後,服務器和客戶端之間交換數據時,用於協議控制的數據包頭部相對較小。在不包含擴展的狀況下,對於服務器到客戶端的內容,此頭部大小隻有2至10字節(和數據包長度有關);對於客戶端到服務器的內容,此頭部還須要加上額外的4字節的掩碼。相對於HTTP請求每次都要攜帶完整的頭部,此項開銷顯著減小了。
更強的實時性:因爲協議是全雙工的,因此服務器能夠隨時主動給客戶端下發數據。相對於HTTP請求須要等待客戶端發起請求服務端才能響應,延遲明顯更少
保持鏈接狀態:Websocket須要先建立鏈接,這就使得其成爲一種有狀態的協議,以後通訊時能夠省略部分狀態信息。而HTTP請求可能須要在每一個請求都攜帶狀態信息(如身份認證等)。
更好的二進制支持:Websocket定義了二進制幀,相對HTTP,能夠更輕鬆地處理二進制內容。
簡單來說,WebSocket協議由兩部分組成:創建鏈接過程(握手) 和 數據傳輸。
在第一部分的介紹中,咱們提到,WebSocket在建立持久性鏈接以前,須要進行一次握手,並且爲了兼容性考慮,WebSocket複用了HTTP的握手通道。具體指的是,客戶端經過HTTP請求與WebSocket服務端協商升級協議。協議升級完成以後,後續的數據交換則遵守WebSocket的協議。
首先,客戶端發起協議升級請求,從下圖能夠看到,採用的是標準的HTTP報文格式,且只支持 GET
方法。
重點說明一下上面四處的意義:
Connection:Upgrade
:表示要升級協議Upgrade:WebSocket
:表示要升級到WebSocket協議Sec-WebSocket-Key
與後面服務器端響應首部的Sec-WebSocket-Accept
是配套的,提供基本的防禦,好比惡意的連接,或者無心的鏈接Sec-WebSocket-Version: 13
:表示WebSocket的版本。若是服務器不支持該版本,須要返回一個Sec-WebSocket-Version
的header
,裏面包含服務端支持的版本號注意,上面請求省略了部分非重點請求首部。因爲是標準的HTTP請求,相似Host、Origin、Cookie等請求首部會照常發送。在握手階段,能夠經過相關請求首部進行 安全限制、權限校驗等。
服務端返回內容以下,狀態碼 101
表示協議切換。到此完成協議升級,後序的數據交互都按照新的協議進行。
Sec-WebSocket-Accept
根據客戶端請求首部的Sec-WebSocket-Key
計算出來。
計算公式爲:
將Sec-WebSocket-Key
跟258EAFA5-E914-47DA-95CA-C5AB0DC85B11
拼接。 經過SHA1
計算出摘要,並轉成base64
字符串。 僞代碼以下:
>toBase64( sha1( Sec-WebSocket-Key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ) )
複製代碼
一旦WebSocket客戶端、服務端創建鏈接後,後續的操做都是基於數據幀的傳遞。
由於此處涉及到了數據幀的知識,因此能夠先查看2.3 數據幀格式的部分。
一、數據分片
WebSocket的每條消息可能被切分紅多個數據幀。當WebSocket的接收方收到一個數據幀時,會根據FIN
的值來判斷,是否已經收到消息的最後一個數據幀。
FIN=1
表示當前數據幀爲消息的最後一個數據幀,此時接收方已經收到完整的消息,能夠對消息進行處理。FIN=0
,則接收方還須要繼續監聽接收其他的數據幀。
此外,opcode
在數據交換的場景下,表示的是數據的類型。0x01
表示文本,0x02
表示二進制。而0x00
比較特殊,表示延續幀(continuation frame
),顧名思義,就是完整消息對應的數據幀還沒接收完。
二、數據分片例子
直接看例子更形象些。下面例子來自MDN,能夠很好地演示數據的分片。客戶端向服務端兩次發送消息,服務端收到消息後迴應客戶端,這裏主要看客戶端往服務端發送的消息。
第一條消息
FIN=1
, 表示是當前消息的最後一個數據幀。服務端收到當前數據幀後,能夠處理消息。opcode=0x1,表示客戶端發送的是文本類型。
第二條消息
FIN=0,opcode=0x1
,表示發送的是文本類型,且消息還沒發送完成,還有後續的數據幀。
FIN=0,opcode=0x0
,表示消息還沒發送完成,還有後續的數據幀,當前的數據幀須要接在上一條數據幀以後。
FIN=1,opcode=0x0
,表示消息已經發送完成,沒有後續的數據幀,當前的數據幀須要接在上一條數據幀以後。服務端能夠將關聯的數據幀組裝成完整的消息。
Client: FIN=1, opcode=0x1, msg="hello"
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg="and a"
Server: (listening, new message containing text started)
Client: FIN=0, opcode=0x0, msg="happy new"
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg="year!"
Server: (process complete message) Happy new year to you too!
複製代碼
客戶端、服務端數據的交換,離不開數據幀格式的定義。因此咱們在這裏看一看WebSocket的數據幀格式。
客戶端、服務端數據的交換,離不開數據幀格式的定義。所以,在實際講解數據交換以前,咱們先來看下WebSocket的數據幀格式。
WebSocket客戶端、服務端通訊的最小單位是幀(frame),由1個或多個幀組成一條完整的消息(message)。
發送端:將消息切割成多個幀,併發送給服務端;
接收端:接收消息幀,並將關聯的幀從新組裝成完整的消息;
本節的重點,就是講解數據幀的格式。
一、數據幀格式概覽
下面給出了WebSocket數據幀的統一格式。
從左到右,單位是比特。好比FIN、RSV1
各佔據1比特,opcode
佔據4比特。 內容包括了標識、操做代碼、掩碼、數據、數據長度等。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
複製代碼
二、數據幀格式詳解
針對前面的格式概覽圖,這裏逐個字段進行講解,能夠參考協議規範。
FIN:1個比特。
若是是1,表示這是消息(message)的最後一個分片(fragment),若是是0,表示不是是消息(message)的最後一個分片(fragment)。
RSV1, RSV2, RSV3:各佔1個比特。
通常狀況下全爲0。當客戶端、服務端協商採用WebSocket擴展時,這三個標誌位能夠非0,且值的含義由擴展進行定義。若是出現非零的值,且並無採用WebSocket擴展,鏈接出錯。
Opcode: 4個比特。
操做代碼,Opcode
的值決定了應該如何解析後續的數據載荷(data payload
)。若是操做代碼是不認識的,那麼接收端應該斷開鏈接(fail the connection
)。可選的操做代碼以下:
%x0
:表示一個延續幀。當Opcode
爲0時,表示本次數據傳輸採用了數據分片,當前收到的數據幀爲其中一個數據分片。
%x1
:表示這是一個文本幀(frame)
%x2
:表示這是一個二進制幀(frame)
%x3-7
:保留的操做代碼,用於後續定義的非控制幀。
%x8
:表示鏈接斷開。
%x9
:表示這是一個ping
操做。
%xA
:表示這是一個pong
操做。
%xB-F
:保留的操做代碼,用於後續定義的控制幀。
Mask: 1個比特
表示是否要對數據載荷進行掩碼操做。從客戶端向服務端發送數據時,須要對數據進行掩碼操做;從服務端向客戶端發送數據時,不須要對數據進行掩碼操做。
若是服務端接收到的數據沒有進行過掩碼操做,服務端須要斷開鏈接。
若是Mask
是1,那麼在Masking-key
中會定義一個掩碼鍵(masking key
),並用這個掩碼鍵來對數據載荷進行反掩碼。全部客戶端發送到服務端的數據幀,Mask
都是1。
Payload length:數據載荷的長度,單位是字節。爲7位,或7+16位,或1+64位
假設數Payload length === x
,若是
x爲0~126:數據的長度爲x字節。
x爲126:後續2個字節表明一個16位的無符號整數,該無符號整數的值爲數據的長度。
x爲127:後續8個字節表明一個64位的無符號整數(最高位爲0),該無符號整數的值爲數據的長度。
此外,若是payload length
佔用了多個字節的話,payload length
的二進制表達採用網絡序(big endian,重要的位在前)。
Masking-key:0或4字節(32位)
全部從客戶端傳送到服務端的數據幀,數據載荷都進行了掩碼操做,Mask爲1,且攜帶了4字節的Masking-key
。若是Mask爲0,則沒有Masking-key
。
備註:載荷數據的長度,不包括mask key的長度。
Payload data:(x+y) 字節
載荷數據:包括了擴展數據、應用數據。其中,擴展數據x字節,應用數據y字節。
擴展數據:若是沒有協商使用擴展的話,擴展數據數據爲0字節。全部的擴展都必須聲明擴展數據的長度,或者能夠如何計算出擴展數據的長度。此外,擴展如何使用必須在握手階段就協商好。若是擴展數據存在,那麼載荷數據長度必須將擴展數據的長度包含在內。
應用數據:任意的應用數據,在擴展數據以後(若是存在擴展數據),佔據了數據幀剩餘的位置。載荷數據長度 減去 擴展數據長度,就獲得應用數據的長度。
三、掩碼算法 掩碼鍵(Masking-key
)是由客戶端挑選出來的32位的隨機數。掩碼操做不會影響數據載荷的長度。掩碼、反掩碼操做都採用以下算法:
首先,假設:
original-octet-i
:爲原始數據的第i字節。
transformed-octet-i
:爲轉換後的數據的第i字節。
j
:爲i mod 4
的結果。
masking-key-octet-j
:爲mask key
第j字節。
算法描述爲: original-octet-i
與 masking-key-octet-j
異或後,獲得 transformed-octet-i
。
j = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j
複製代碼
WebSocket爲了保持客戶端、服務端的實時雙向通訊,須要確保客戶端、服務端之間的TCP通道保持鏈接沒有斷開。然而,對於長時間沒有數據往來的鏈接,若是依舊長時間保持着,可能會浪費包括的鏈接資源。
但不排除有些場景,客戶端、服務端雖然長時間沒有數據往來,但仍須要保持鏈接。這個時候,能夠採用心跳來實現。
ping
接收方->發送方:`pong` `ping`、`pong的操做`,對應的是WebSocket的兩個控制幀,`opcode
分別是0x9、
0xA`。在這一部分最後,在說明兩個知識點(不作詳細說明)
1.Sec-WebSocket-Key/Accept
的做用:主要做用在於提供基礎的防禦,減小惡意鏈接、意外鏈接。 做用大體概括以下:
避免服務端收到非法的websocket鏈接(好比http客戶端不當心請求鏈接websocket服務,此時服務端能夠直接拒絕鏈接)
確保服務端理解websocket鏈接。由於ws
握手階段採用的是http協議,所以可能ws鏈接是被一個http服務器處理並返回的,此時客戶端能夠經過Sec-WebSocket-Key
來確保服務端認識ws
協議。(並不是百分百保險,好比老是存在那麼些無聊的http服務器,光處理Sec-WebSocket-Key
,但並無實現ws協議。。。)
用瀏覽器裏發起ajax請求,設置header時,Sec-WebSocket-Key
以及其餘相關的header是被禁止的。這樣能夠避免客戶端發送ajax請求時,意外請求協議升級(websocket upgrade
)
能夠防止反向代理(不理解ws協議)返回錯誤的數據。好比反向代理先後收到兩次ws
鏈接的升級請求,反向代理把第一次請求的返回給cache住,而後第二次請求到來時直接把cache住的請求給返回(無心義的返回)。
Sec-WebSocket-Key
主要目的並非確保數據的安全性,由於Sec-WebSocket-Key、Sec-WebSocket-Accept
的轉換計算公式是公開的,並且很是簡單,最主要的做用是預防一些常見的意外狀況(非故意的)。
2. 數據掩碼的做用:
WebSocket協議中,數據掩碼的做用是加強協議的安全性(並非爲了防止數據泄密,而是爲了防止早期版本的協議中存在的代理緩存污染攻擊(proxy cache poisoning attacks
)等問題。)。但數據掩碼並非爲了保護數據自己,由於算法自己是公開的,運算也不復雜。除了加密通道自己,彷佛沒有太多有效的保護通訊安全的辦法。
<input type="text" id="sendTxt">
<button id="sendBtn">發送</button>
<div id="recv"></div>
<script>
/**
* WebSocket對象做爲一個構造函數,用於新建WebSocket實例
* 執行下面的語句以後,客戶端就會個服務器進行鏈接
*/
let webSocket = new WebSocket("wss://echo.websocket.org");
/**
* 下面結合實際講一下WebSocket實例對象的屬性和方法
* 1. 屬性
* 1.1 webSocket.readyState(屬性返回實例對象的當前狀態)
* . CONNECTING:值爲0,表示正在鏈接。
* . OPEN:值爲1,表示鏈接成功,能夠通訊了。
* . CLOSING:值爲2,表示鏈接正在關閉。
* . CLOSED:值爲3,表示鏈接已經關閉,或者打開鏈接失敗。
*/
/**
* 1.2 webSocket.onopen(用於指定鏈接成功後的回調函數)
*/
webSocket.onopen = function () {
console.log("webSocket open");
document.getElementById('recv').innerHTML = "Connected";
};
/**
* 1.3 webSocket.onclose(用於指定鏈接關閉以後的回調函數)
*/
webSocket.onclose = function () {
console.log("webSocket close");
}
/**
* 1.4 webSocket.onmessage(用於指定收到服務器數據後的回調函數)
*/
webSocket.onmessage = function (e) {
console.log(e.data);
document.getElementById('recv').innerHTML = e.data;
}
//發送信息
document.getElementById('sendBtn').onclick = function () {
var text = document.getElementById('sendTxt').value;
/**
* 2. 方法
* 2.1 webSocket.send() (用於向服務器發送數據)
*/
webSocket.send(text);
}
</script>
複製代碼
客戶端的API上面的代碼中有簡單的介紹以及使用,若是想要查看更加具體的文檔說明,能夠在MDN進行查看。
對比於服務端的實現,客戶端的使用略顯簡單,那麼接下來咱們繼續實現服務端的WebSocket。
由於筆者目前侷限於JS,因此服務端的實現是使用的Node,經常使用的Node實現有如下三種:
µWebSockets
Socket.IO
WebSocket-Node
由於在項目中使用的是Socket.IO
,因此在這裏筆者就結合本身的親身經歷去講解如下,其餘的實現方式應該也是差很少的,有興趣的話是能夠本身實現一些的。
Socket.IO
想實現雙向通訊,固然WebSocket是必不可少的技術了,不過Socket.IO
不只僅是WebSocket的封裝,在不支持WebSocket的環境中,Socket.IO
還有多種輪詢解決方案,確保它可以正常運行。
既然用到了Socket.IO
,那咱們就要扒一扒有關於它的介紹,基本使用等等內容,先在這裏貼一個官方文檔。由於官方文檔爲全英,這裏筆者找到了一個中文文檔,建議二者對比着看,有能力的固然仍是看全英的比較好,內容更加準確。
Socket.Io
主要由兩個部分組成:
socket.io
模塊,集成到Node.js
的http
模塊的服務器
socket.io-client
,在瀏覽器中運行的客戶端 Socket.Io
支持多種傳輸機制,例如WebSocket、Adobe Flash Sockets、XHR輪詢、JsonP輪詢
,它們被隔離在統一的接口之下,這意味着任何瀏覽器均可以做爲客戶端。
標準的WebSocket服務器並不能和Socket.Io
客戶端進行直接通訊,須要注意這一點。
Socket.io
是一個WebSocket庫,包括了客戶端的js
和服務器端的nodejs
,它的目標是構建能夠在不一樣瀏覽器和移動設備上使用的實時應用。它會自動根據瀏覽器從WebSocket
、AJAX
長輪詢、Iframe
流等等各類方式中選擇最佳的方式來實現網絡實時應用,很是方便和人性化,並且支持的瀏覽器最低達IE5.5。
如今Node.js的框架很是的多,譬如:Express、ThinkJS、Koa、Egg.js等,每個框架有可能進一步對Socket.io
進行了封裝,好比筆者使用過的Egg.js框架就提供了 egg-socket.io
插件,使用這些插件就要遵循框架的一些約束,因此對於框架中的使用,仍是須要讀者根據文檔要求使用,由於這個因素,因此讀者只在這裏介紹在不使用任何框架的狀況下的使用。
安裝
$ npm install socket.io
複製代碼
使用 Node http 服務器
先直接上代碼(最基礎),以後會根據官方文檔講解其餘內容。
// index.html
<script src="./node_modules/socket.io-client/dist/socket.io.js"></script>
<script>
let socket = io('http://localhost');
socket.on('news', (data) => { //監聽'news'事件,有結果後輸出
console.log(data);
socket.emit('my other event', { //觸發'my other event'事件
my: 'data'
})
})
</script>
// app.js
let app = require('http').createServer(handler);//使用Node建立一個Http服務
let io = require('socket.io')(app); //此處爲綁定上面建立的服務器
let fs = require('fs');
app.listen(80);
var handler = (req, res) => {
fs.readFile(__dirname + './index.html', (err, data) => {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
})
}
io.on('connection', (socket) => {
socket.emit('news', { //觸發'news'事件
hello: 'world'
});
socket.on('my other event', (data) => { //監聽'my other event'事件,有結果後輸出
console.log(data);
})
})
複製代碼
上面代碼完成後,運行 node app.js
,以後打開 index.html
,以後再打開瀏覽器的控制檯,會發現瀏覽器的控制檯上先打印出{hello: "world"}
,以後編輯器的控制檯上打印出{my: "data"}
,注意兩個是有前後順序的,這個看代碼就明白了,很少說。
emit
和 on
是最重要的兩個api,分別對應 發送 和 監聽 事件。
socket.emit(eventName[, ...args])
:發射(觸發)一個事件
socket.on(eventName, callback)
:監聽一個emit
發射的事件
咱們能夠很是自由的在服務端定義併發送一個事件emit
,而後在客戶端監聽 on
,反過來也同樣。 發送的內容格式也很是自由,既能夠是基本數據類型 Number,String,Boolean
等,也能夠是Object,Array
類型,甚至還能夠是函數。而用回調函數的方式則能夠進行更便攜的交互。
1.2 部分的示例代碼就是這兩個api的使用,這裏就很少說了。
broadcast
默認是向全部的socket鏈接進行廣播,可是不包括髮送者自身。
注意:socket鏈接要確保是同一個命名空間下的
代碼解釋:
io.on('connection', (socket) => {
//發送給除本身之外的其餘客戶端
socket.broadcast.emit('news', {
hello: 'world'
})
})
複製代碼
此時,要想查看效果,能夠在建立一個HTML頁面,代碼同樣便可,以後在瀏覽器上同時打開兩個頁面,刷新一個頁面時(刷新一次頁面就至關於觸發一次事件),本頁面控制檯沒有輸出任何內容,另外一個頁面的控制檯則會輸出內容(能夠建立更多頁面查看效果)。
若是想要自身也能夠收到消息,此時能夠
io.on('connection', (socket) => {
//發送給本身
socket.emit('news', {
hello: 'world'
})
})
複製代碼
所謂的命名空間,就是指在不一樣的域當中發消息只能給當前的域的socket收到。
做用:能夠最大限度地減小資源(TCP鏈接)的數量,,併爲應用提供頻道劃分功能。(這樣多個應用模塊能夠共享單個TCP鏈接)
若是想隔離做用域,或者劃分業務模塊,這時候就可使用命名空間,命名空間至關於創建新的頻道,使你能夠在一個socket.io服務上隔離不一樣的鏈接,時間和中間件。
默認的命名空間是/
,Socket.IO 客戶端默認鏈接到這個命名空間,服務端默認監聽的也是這個命名空間。
自定義命名空間
重要提示:命名空間是 Socket.IO 協議的一個實現細節, 與底層傳輸的實際 URL 無關。底層傳輸的實際 URL 默認是/socket.io/…
。
使用命名空間的方式一:直接在連接後面加子域名,這種方式其實仍是用同一個socket服務進程---軟隔離
服務端代碼:
io
.of('my-nsp')
.on('connection', (socket) => {
// 發送給除本身之外的其餘客戶端
socket.broadcast.emit('news', {
hello: 'world'
})
//發送給本身
socket.emit('news', {
hello: 'world'
})
})
複製代碼
客戶端須要修改的代碼:
let socket = io('http://localhost:3000/my-nsp');
複製代碼
使用命名空間的方式二:path
參數,這種方式就是真正的從新開啓了一個socket服務。
這裏說一下,namespace
、room
和socket
的關係
socket
會屬於某一個 room
,若是沒有指定,那麼會有一個默認的room
。這個room
又會屬於某個namespace
,若是沒有指定,那麼就是默認的/
。(一個命名空間下能夠有多個room
)
客戶端鏈接時指定本身屬於哪個 namespace
,服務端看到namespace
就會把這個socket
加入到指定的namespace
中,若是客戶端沒有指定具體的room
,則服務端會放入默認的room
,或者服務端經過代碼socket.join(bar)
放入bar
的room
中。
默認狀況下,每個id
便自成一個房間,房間名是 socket.id
(指定命名空間以後,前面會帶上命名空間,socket會自動加入到以此ID來標識的房間);自定義房間以後,原先的默認控件仍然存在;房間爲一個對象,包含當前進入房間的sockets以及長度。
代碼示例:
io
.on('connection', (socket) => {
//在服務端將一個socket加入到一個房間中
socket.join('manannan', () => {
console.log(socket.rooms);
});
//進入到該房間中,以後的事件發佈僅僅在這個房間
io.to('manannan').emit('news', {
hello: 'world'
})
//離開房間
socket.leave('mananan')
})
複製代碼
以上內容就是基本的使用,然而在實際項目中,確定會比這些更加複雜,這裏就不一一贅述,當咱們用到咱們以前沒有用過的東西時,必定要善於查看官方文檔以及百度。
因此關於客戶端API和服務端API等更多的內容,須要時查看官方文檔就能夠了。