WebSocket JavaScript API

WebSocket是HTML5提供的一種在單個(gè)TCP連接上進(jìn)行全雙工通信(雙向通信)的協(xié)議,WebSocket使客戶(hù)端和服務(wù)端之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶(hù)端推送數(shù)據(jù)。

Web中已經(jīng)有了HTTP協(xié)議,為什么還需要WebSocket協(xié)議呢?

由于HTTP協(xié)議有一個(gè)天生的缺陷:通信只能由客戶(hù)端發(fā)起,因此HTTP協(xié)議做不到服務(wù)器主動(dòng)向客戶(hù)端推送信息。

HTTP 與 WebSocket

HTTP這種單向請(qǐng)求的特點(diǎn),注定了如果服務(wù)器有連續(xù)的狀態(tài)變化,客戶(hù)端要獲知就必須采用輪詢(xún)的方式。而輪詢(xún)的效率低下且非常浪費(fèi)資源,因?yàn)楸仨毑煌5剡B接或者讓HTTP連接始終打開(kāi)。此時(shí),也就出現(xiàn)了WebSocket。

AJAX輪詢(xún)與WebSocket

WebSocket協(xié)議誕生于2008年,2011年成為國(guó)際標(biāo)準(zhǔn),主流瀏覽器均已經(jīng)得到支持。WebSocket協(xié)議最大的特點(diǎn)是服務(wù)器可以主動(dòng)的向客戶(hù)端推送信息,客戶(hù)端也可以主動(dòng)的向服務(wù)器發(fā)送信息,它是真正的雙向平等對(duì)話(huà),屬于服務(wù)器推送技術(shù)的一種。

WebSocket協(xié)議的特點(diǎn)

  • WebSocket協(xié)議建立在TCP協(xié)議之上,服務(wù)器實(shí)現(xiàn)比較容易。
  • WebSocket協(xié)議與HTTP協(xié)議有著良好的兼容性,默認(rèn)端口是80和443,握手階段采用HTTP協(xié)議因此不容易屏蔽,能通過(guò)各種HTTP代理服務(wù)器。
  • WebSocket數(shù)據(jù)格式比較輕量,性能開(kāi)銷(xiāo)較小,通信高效。
  • WebSocket可以發(fā)送文本也可以發(fā)送二進(jìn)制數(shù)據(jù)
  • WebSocket沒(méi)有同源限制,客戶(hù)端可以與任意服務(wù)器通信。
  • WebSocket協(xié)議標(biāo)識(shí)符是wswss,服務(wù)器地址直接是URL。
WebSocket

WebSocket API

WebSocket包含網(wǎng)絡(luò)協(xié)議與API,讓用戶(hù)能夠在客戶(hù)端和服務(wù)端創(chuàng)建WebSocket連接。WebSocketAPI是使用WebSocket協(xié)議的接口,通過(guò)它來(lái)創(chuàng)建全雙工通道以收發(fā)消息。

WebSocketAPI是純事件驅(qū)動(dòng),一旦建立全雙工鏈接,當(dāng)服務(wù)端給客戶(hù)端發(fā)送數(shù)據(jù)或資源時(shí)能自動(dòng)發(fā)送狀態(tài)改變的數(shù)據(jù)和通知。所以不需要為了狀態(tài)的更新而去輪詢(xún)服務(wù)器,只需要在客戶(hù)端監(jiān)聽(tīng)即可。

在WebSocket的API中,客戶(hù)端和服務(wù)端只需要完成一次握手動(dòng)作,然后客戶(hù)端與服務(wù)端之間就會(huì)形成一條快速通道,兩者之間就可以直接創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

客戶(hù)端通過(guò)JavaScript向服務(wù)端發(fā)起建立WebSocket連接的握手請(qǐng)求,當(dāng)連接建立成功以后,客戶(hù)端和服務(wù)端就可以通過(guò)TCP連接直接交換數(shù)據(jù),當(dāng)獲取WebSocket連接后,可通過(guò)send()方法來(lái)向服務(wù)端發(fā)送數(shù)據(jù),客戶(hù)端通過(guò)onmessage事件來(lái)接收服務(wù)端返回的數(shù)據(jù)。

WebSocket協(xié)議本質(zhì)

WebSocket協(xié)議本質(zhì)上是一個(gè)基于TCP的協(xié)議 ,為了建立一個(gè)WebSocket連接,客戶(hù)端瀏覽器首先要向服務(wù)器發(fā)起一個(gè)HTTP握手請(qǐng)求,這個(gè)請(qǐng)求和通常的HTTP請(qǐng)求有所不同,它包含了一些附加的頭信息,其中會(huì)附加頭信息Upgrade: WebSocket表明這是一個(gè)申請(qǐng)協(xié)議升級(jí)的HTTP請(qǐng)求。服務(wù)器解析這些附加的頭信息后會(huì)產(chǎn)生應(yīng)答信息并返回給客戶(hù)端,客戶(hù)端和服務(wù)器的WebSocket連接就會(huì)建立起來(lái),雙方就可以通過(guò)連接通道自由的傳遞信息,并且這個(gè)連接會(huì)持續(xù)存在直到客戶(hù)端或服務(wù)器的某一方主動(dòng)關(guān)閉連接。

客戶(hù)端發(fā)送的典型WebSocket握手請(qǐng)求

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

服務(wù)器回應(yīng)的WebSocket典型握手響應(yīng)

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

WebSocket專(zhuān)有字段分析

  • Upgrade: websocket

Upgrade字段必須設(shè)置為websocket,表示客戶(hù)端希望連接升級(jí)到websocket協(xié)議。

  • Connection: Upgrade

Connection必須設(shè)置為Upgrade,表示客戶(hù)端希望連接升級(jí)

  • Sec-WebSocket-Key

Sec-WebSocket-Key是隨機(jī)字符串,服務(wù)器會(huì)使用它來(lái)構(gòu)造出一個(gè)SHA-1的信息摘要,將Sec-WebSocket-Key加上一個(gè)特殊的字符串,然后計(jì)算出SHA-1摘要,之后在進(jìn)行BASE-64編碼,最終結(jié)果作為Sec-WebSocket-Accept頭的值返回給客戶(hù)端。如此操作,可以盡量避免普通HTTP請(qǐng)求被誤認(rèn)為WebSocket協(xié)議。

  • Sec-WebSocket-Version

Sec-WebSocket-Version表示支持的WebSocket版本,RFC6455要求使用的版本是13,之前草案的版本均應(yīng)當(dāng)棄用。

  • Origin

Origin字段是可選的,通常用來(lái)表示在瀏覽器中發(fā)起此WebSocket連接所在的頁(yè)面,類(lèi)似于Referer。但是與Referer不同的是,Origin只包含了協(xié)議和主機(jī)名稱(chēng)。

WebSocket與 Socket有什么區(qū)別呢?

在軟件通信的七層架構(gòu)中下三層結(jié)構(gòu)偏向于數(shù)據(jù)通信,上三層偏向于數(shù)據(jù)處理,中間的傳輸層則是連接上三層和下三層之間的橋梁,每一層都做著不同的工作,上層協(xié)議 依賴(lài)于下層協(xié)議。

Socket其實(shí)并不是一個(gè)協(xié)議,而是應(yīng)用層與TCP/IP協(xié)議簇通信的中間軟件抽象層,它是一組接口。當(dāng)兩臺(tái)主機(jī)通信的時(shí)候,會(huì)讓Socket去組織數(shù)據(jù)以符合指定的協(xié)議。TCP連接則更依賴(lài)于底層的IP協(xié)議,IP協(xié)議的連接則依賴(lài)于鏈路層等更低層次。

WebSocket則是一個(gè)典型的應(yīng)用層協(xié)議,總體而言,Socket是傳輸控制層協(xié)議,WebSocket則是應(yīng)用層協(xié)議。

構(gòu)造函數(shù)

首先需要通過(guò)調(diào)用WebSocket的構(gòu)造函數(shù)來(lái)創(chuàng)建WebSocket連接,構(gòu)造函數(shù)會(huì)返回一個(gè)WebSocket實(shí)例,用來(lái)監(jiān)聽(tīng)事件。

WebSocket構(gòu)造函數(shù)需要傳入一個(gè)URL參數(shù)和一個(gè)可選的協(xié)議參數(shù)

var ws = new WebSocket(url, [protocol]);
console.log(ws);
WebSocket對(duì)象

構(gòu)造函數(shù)的第一個(gè)參數(shù)是URL,WebSocket協(xié)議定義了兩種URL方案,WS和WSS分別代表了客戶(hù)端和服務(wù)端之間未加密的通信。WS(WebSocket)類(lèi)似于HTTP的URL,WSS(WebSocket Security)的URL表示連接是基于安全傳輸層(TLS/SSL),和HTTPS的連接使用的是同樣的安全機(jī)制。URL參數(shù)需要以ws://wss://開(kāi)頭,如果URL存在語(yǔ)法錯(cuò)誤構(gòu)造函數(shù)會(huì)拋出異常。

構(gòu)造函數(shù)的第二個(gè)參數(shù)是協(xié)議名稱(chēng),是可選的,服務(wù)端和客戶(hù)端使用的協(xié)議必須保持一致,這樣收發(fā)消息時(shí)彼此才能理解。雖然可以定義一個(gè)或多個(gè)客戶(hù)端使用的協(xié)議,但服務(wù)端只會(huì)選擇一個(gè)來(lái)使用,一個(gè)客戶(hù)端和一個(gè)服務(wù)端只能有一個(gè)協(xié)議,而且都必須基于WebSocket。協(xié)議名稱(chēng)參數(shù)支持XMPP(Extensible Messaging and Presence Protocol)、SOAP(Simple Object Access Protocol)或自定義協(xié)議。

WebSocket對(duì)象的屬性

ws.readyState

只讀屬性readState表示當(dāng)前連接狀態(tài),可選值包括

  • 0 WebSocket.CONNECTING 表示連接正在建立中但尚未建立
  • 1 WebSocket.OPEN 表示連接已經(jīng)建立可以發(fā)送消息進(jìn)行通信
  • 2 WebSocket.CLOSING表示連接正在進(jìn)行關(guān)閉握手
  • 3 WebSocket.CLOSED 表示連接已經(jīng)關(guān)閉或連接不能打開(kāi)

ws.bufferedAmount

只讀屬性bufferedAmount表示已經(jīng)被send()放入正在隊(duì)列中等待傳輸,但還沒(méi)有發(fā)出的UTF-8文本字節(jié)數(shù)。當(dāng)需要檢查傳輸數(shù)據(jù)大小時(shí),尤其是客戶(hù)端傳輸大量數(shù)據(jù)時(shí),雖然send()方法會(huì)馬上執(zhí)行,但數(shù)據(jù)并不是馬上傳輸。瀏覽器會(huì)緩存應(yīng)用流出的數(shù)據(jù),可以使用bufferedAmount屬性檢查已經(jīng)進(jìn)入隊(duì)列但未被傳輸?shù)臄?shù)據(jù)大小。bufferedAmount值不包括協(xié)議框架、操作系統(tǒng)緩存和網(wǎng)絡(luò)軟件的開(kāi)銷(xiāo)。

例如:使用bufferedAmount屬性每秒更新發(fā)送,如果網(wǎng)絡(luò)不能處理這個(gè)頻率會(huì)自動(dòng)適應(yīng)。

//判斷瀏覽器是否支持WebSocket
if(window.WebSocket)
{
    console.log("This browser supports WebSocket");
}
else
{
    console.log("This browser does not support WebSocket");
}

//10K
var THRESHOLD = 10240;

//建立連接
var url = "ws://echo.websocket.org";
var ws = new WebSocket(url);

//監(jiān)聽(tīng)握手請(qǐng)求
ws.onopen = function()
{
    setInterval(function(){
        //如果緩存未滿(mǎn)時(shí)發(fā)送數(shù)據(jù),使用bufferedAmount屬性發(fā)送數(shù)據(jù)可以避免網(wǎng)絡(luò)飽和。
        if(ws.bufferedAmount < THRESHOLD){
            ws.send(getApplicationState());
        }
    }, 1000);
}

ws.protocol

在構(gòu)造函數(shù)中protocol參數(shù)會(huì)讓服務(wù)器知道客戶(hù)端使用的WebSocket協(xié)議,WebSocket對(duì)象的protocol屬性是指最終服務(wù)器確定下來(lái)的協(xié)議名稱(chēng),當(dāng)服務(wù)器沒(méi)有選擇客戶(hù)端提供的協(xié)議或在連接握手之前,此屬性為空。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-WebSo...
    敢夢(mèng)敢當(dāng)閱讀 9,032評(píng)論 0 50
  • WebSocket 機(jī)制 WebSocket 是 HTML5 一種新的協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,能更...
    勇敢的_心_閱讀 2,380評(píng)論 0 4
  • 1.延展 可以定義私有屬性和方法#import "MyClass.h" @interface MyClass ()...
    iOS小菜鳥(niǎo)閱讀 236評(píng)論 0 1
  • 2009-06-25 17:11:25 從來(lái)沒(méi)有迫害,也沒(méi)有解救。美人,根本就是叢自我催眠的水仙。嗜睡是源于內(nèi)心的...
    四兩金閱讀 186評(píng)論 0 1
  • 作者:尚小英 主題:27天的日常 DAY2 標(biāo)題:迷茫的“老年人”2 正文:話(huà)說(shuō)一時(shí)迷茫,一時(shí)爽,一直迷茫,一直爽...
    陳束閱讀 186評(píng)論 0 1

友情鏈接更多精彩內(nèi)容