有幾點需要首先明確:
1. websocket是一種協(xié)議憎茂。是html5的一種新協(xié)議;
2. 與http的區(qū)別是惕鼓,它是一種雙向通信協(xié)議,服務(wù)器和客戶端都能主動向?qū)Ψ桨l(fā)送或接受數(shù)據(jù)涯贞;
3. websocket需要進(jìn)行握手連接之后才能進(jìn)行通信扎谎;
那么我們就知道了websocket誕生的意義了:
傳統(tǒng)的http的請求方式,是客戶端發(fā)送請求服務(wù)端響應(yīng)的形式岭皂,這種方式在應(yīng)對信息變化不是很頻繁的應(yīng)用時還能較好應(yīng)對郊霎,但是對于實時要求高、海量并發(fā)的應(yīng)用來說顯得捉襟見肘爷绘,尤其在當(dāng)前業(yè)界移動互聯(lián)網(wǎng)蓬勃發(fā)展的趨勢下,高并發(fā)與用戶實時響應(yīng)是 Web 應(yīng)用經(jīng)常面臨的問題进倍,比如金融證券的實時信息土至,Web 導(dǎo)航應(yīng)用中的地理位置獲取,社交網(wǎng)絡(luò)的實時消息推送等猾昆。
基于http陶因,我們也有實時通訊的方案,比如輪詢垂蜗,比如使用flash的socket楷扬,但是這些都是非標(biāo)準(zhǔn)的,而且代價較大贴见,html5的標(biāo)準(zhǔn)化組織需要針對實時通訊的應(yīng)用場景提供一套業(yè)界統(tǒng)一的規(guī)范烘苹,那就是websocket。
socket通信方式
socket的概念最初出現(xiàn)在linux網(wǎng)絡(luò)編程中片部,socket是在應(yīng)用層和傳輸層之間的一個抽象層镣衡,它把TCP/IP層復(fù)雜的操作抽象為幾個簡單的接口供應(yīng)用層調(diào)用已實現(xiàn)進(jìn)程在網(wǎng)絡(luò)中通信。
簡而言之,socket就是對TCP連接建立和釋放的過程進(jìn)行了一層封裝廊鸥,提供出接口給應(yīng)用層是使用望浩。
socket是如何與對應(yīng)網(wǎng)絡(luò)中的進(jìn)程進(jìn)行通信的呢?
我們知道兩個進(jìn)程如果需要進(jìn)行通訊最基本的一個前提能能夠唯一的標(biāo)示一個進(jìn)程惰说,在本地進(jìn)程通訊中我們可以使用PID來唯一標(biāo)示一個進(jìn)程磨德,但PID只在本地唯一,網(wǎng)絡(luò)中的兩個進(jìn)程PID沖突幾率很大吆视,這時候我們需要另辟它徑了剖张,我們知道IP層的ip地址可以唯一標(biāo)示主機,而TCP層協(xié)議和端口號可以唯一標(biāo)示主機的一個進(jìn)程揩环,這樣我們可以利用ip地址+協(xié)議+端口號唯一標(biāo)示網(wǎng)絡(luò)中的一個進(jìn)程搔弄。
那么在進(jìn)行socket接口調(diào)用了時候,傳遞上述唯一標(biāo)識之后丰滑,生成相應(yīng)的協(xié)議請求顾犹,雙向通信就能通過socket進(jìn)行了。
web socket的作用也是模仿socket的通信能力褒墨,但是不同的是炫刷,他本身是一種協(xié)議,瀏覽器和服務(wù)端會對這種協(xié)議進(jìn)行解析郁妈,他是基于基礎(chǔ)TCP連接的浑玛,所以本身它是具有建立雙向連接的能力的,只不過具體的數(shù)據(jù)傳輸方式和一些針對web實時通訊的特性需要在websocket中進(jìn)行定義噩咪。
websocket簡介
傳統(tǒng)的http請求方式:
websocket的通信方式:
可以看到顾彰,http請求每次客戶端與服務(wù)端交互一定得重新建立連接,但是websocket協(xié)只需要雙方通過握手建立連接胃碾,在連接釋放之前涨享,客戶端和服務(wù)端可以相互接收和傳遞數(shù)據(jù),因為雙方通過協(xié)議是知道建立websocket鏈接各自進(jìn)程的端口的仆百。
在客戶端中厕隧,我們需要使用WebSocket對象,去連接ws://這樣的服務(wù)端url俄周,這樣客戶端就會自動解析并識別websocket請求從而和服務(wù)端通過握手建立連接吁讨。
WebSocket 客戶端連接報文
GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: http://localhost:8080
Sec-WebSocket-Version: 13
其中,“Sec-WebSocket-Key”是 WebSocket 客戶端發(fā)送的一個 base64 編碼的密文峦朗,要求服務(wù)端必須返回一個對應(yīng)加密的“Sec-WebSocket-Accept”應(yīng)答建丧,否則客戶端會拋出“Error during WebSocket handshake”錯誤,并關(guān)閉連接甚垦。
WebSocket 服務(wù)端響應(yīng)報文
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
“Sec-WebSocket-Accept”的值是服務(wù)端采用與客戶端一致的密鑰計算出來后返回客戶端的,“HTTP/1.1 101 Switching Protocols”表示服務(wù)端接受 WebSocket 協(xié)議的客戶端連接茶鹃,經(jīng)過這樣的請求-響應(yīng)處理后涣雕,客戶端服務(wù)端的 WebSocket 連接握手成功, 后續(xù)就可以進(jìn)行 TCP 通訊了。
具體參考:websocket協(xié)議棧
websocket的實現(xiàn)
要實現(xiàn)websocket闭翩,必須客戶端和服務(wù)端都要支持這個協(xié)議挣郭。
Tomcat在新版本中提供了WebSocketServlet對象,用于支持websocket疗韵。php肯定也有自己的websocket封裝兑障。
而在客戶端html5提供了標(biāo)準(zhǔn)的websocket API,demo實現(xiàn)如下:
var ws = new WebSocket(“ws://echo.websocket.org”);
ws.onopen = function(){ws.send(“Test!”); };
ws.onmessage = function(evt){console.log(evt.data);ws.close();};
ws.onclose = function(evt){console.log(“WebSocketClosed!”);};
ws.onerror = function(evt){console.log(“WebSocketError!”);};
ws.send("hello");//向服務(wù)器發(fā)送消息
第一行代碼是在申請一個 WebSocket 對象蕉汪,參數(shù)是需要連接的服務(wù)器端的地址流译,同 HTTP 協(xié)議開頭一樣,WebSocket 協(xié)議的 URL 使用 ws://開頭者疤,另外安全的 WebSocket 協(xié)議使用 ws://開頭福澡。
第二行到第五行為 WebSocket 對象注冊消息的處理函數(shù),WebSocket 對象一共支持四個消息 onopen, onmessage, onclose 和 onerror驹马,有了這 4 個事件革砸,我們就可以很容易很輕松的駕馭 WebSocket。
當(dāng) Browser 和 WebSocketServer 連接成功后糯累,會觸發(fā) onopen 消息算利;如果連接失敗,發(fā)送泳姐、接收數(shù)據(jù)失敗或者處理數(shù)據(jù)出現(xiàn)錯誤效拭,browser 會觸發(fā) onerror 消息;當(dāng) Browser 接收到 WebSocketServer 發(fā)送過來的數(shù)據(jù)時胖秒,就會觸發(fā) onmessage 消息缎患,參數(shù) evt 中包含 Server 傳輸過來的數(shù)據(jù);當(dāng) Browser 接收到 WebSocketServer 端發(fā)送的關(guān)閉連接請求時扒怖,就會觸發(fā) onclose 消息较锡。我們可以看出所有的操作都是采用異步回調(diào)的方式觸發(fā),這樣不會阻塞 UI盗痒,可以獲得更快的響應(yīng)時間,更好的用戶體驗低散。
業(yè)務(wù)中websocket的使用
在糯米組件的最新迭代中俯邓,支持使用websocket更新shoplist頁面中的訂單狀態(tài)。
在comp/utils/csocket.js中熔号,定義了c端websocket的封裝稽鞭。
調(diào)用new WebSocket建立websocket連接。
websocket不同階段的回調(diào)引镊。
其中message方法用于給某一類服務(wù)端返回的時間注冊回調(diào)朦蕴。
參考文檔: