WebSocket 原理呼猪,為什么可以實現(xiàn)持久連接?

原文地址:https://www.zhihu.com/question/20215561/answer/40316953
來源:知乎
著作權(quán)歸作者所有砸琅。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)宋距,非商業(yè)轉(zhuǎn)載請注明出處。

一症脂、WebSocket是HTML5出的東西(協(xié)議)谚赎,也就是說HTTP協(xié)議沒有變化,或者說沒關(guān)系诱篷,但HTTP是不支持持久連接的(長連接壶唤,循環(huán)連接的不算)
首先HTTP有1.1和1.0之說,也就是所謂的keep-alive棕所,把多個HTTP請求合并為一個闸盔,但是Websocket其實是一個新協(xié)議,跟HTTP協(xié)議基本沒有關(guān)系琳省,只是為了兼容現(xiàn)有瀏覽器的握手規(guī)范而已迎吵,也就是說它是HTTP協(xié)議上的一種補(bǔ)充可以通過這樣一張圖理解

image

有交集躲撰,但是并不是全部。
另外Html5是指的一系列新的API钓觉,或者說新規(guī)范茴肥,新技術(shù)。Http協(xié)議本身只有1.0和1.1荡灾,而且跟Html本身沒有直接關(guān)系。瞬铸。
通俗來說批幌,你可以用HTTP協(xié)議傳輸非Html數(shù)據(jù),就是這樣=嗓节。=
再簡單來說荧缘,層級不一樣

二拦宣、Websocket是什么樣的協(xié)議截粗,具體有什么優(yōu)點
首先,Websocket是一個持久化的協(xié)議鸵隧,相對于HTTP這種非持久的協(xié)議來說绸罗。
簡單的舉個例子吧,用目前應(yīng)用比較廣泛的PHP生命周期來解釋豆瘫。

  1. HTTP的生命周期通過Request來界定珊蟀,也就是一個Request 一個Response,那么HTTP1.0外驱,這次HTTP請求就結(jié)束了育灸。
    在HTTP1.1中進(jìn)行了改進(jìn),使得有一個keep-alive昵宇,也就是說磅崭,在一個HTTP連接中,可以發(fā)送多個Request瓦哎,接收多個Response砸喻。
    但是請記住 Request = Response , 在HTTP中永遠(yuǎn)是這樣杭煎,也就是說一個request只能有一個response恩够。而且這個response也是被動的,不能主動發(fā)起羡铲。

教練蜂桶,你BB了這么多,跟Websocket有什么關(guān)系呢也切?
(:з」∠)好吧扑媚,我正準(zhǔn)備說Websocket呢腰湾。。
首先Websocket是基于HTTP協(xié)議的疆股,或者說借用了HTTP的協(xié)議來完成一部分握手费坊。
在握手階段是一樣的
-------以下涉及專業(yè)技術(shù)內(nèi)容,不想看的可以跳過lol:旬痹,或者只看加黑內(nèi)容--------
首先我們來看個典型的Websocket握手(借用Wikipedia的附井。。)

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

熟悉HTTP的童鞋可能發(fā)現(xiàn)了两残,這段類似HTTP協(xié)議的握手請求中永毅,多了幾個東西。
我會順便講解下作用人弓。

Upgrade: websocket
Connection: Upgrade

這個就是Websocket的核心了沼死,告訴Apache、Nginx等服務(wù)器:注意啦崔赌,窩發(fā)起的是Websocket協(xié)議意蛀,快點幫我找到對應(yīng)的助理處理~不是那個老土的HTTP。

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

首先健芭,Sec-WebSocket-Key 是一個Base64 encode的值县钥,這個是瀏覽器隨機(jī)生成的,告訴服務(wù)器:泥煤吟榴,不要忽悠窩魁蒜,我要驗證尼是不是真的是Websocket助理。
然后吩翻,Sec_WebSocket-Protocol 是一個用戶定義的字符串兜看,用來區(qū)分同URL下,不同的服務(wù)所需要的協(xié)議狭瞎。簡單理解:今晚我要服務(wù)A细移,別搞錯啦~
最后,Sec-WebSocket-Version 是告訴服務(wù)器所使用的Websocket Draft(協(xié)議版本)熊锭,在最初的時候弧轧,Websocket協(xié)議還在 Draft 階段,各種奇奇怪怪的協(xié)議都有碗殷,而且還有很多期奇奇怪怪不同的東西精绎,什么Firefox和Chrome用的不是一個版本之類的,當(dāng)初Websocket協(xié)議太多可是一個大難題锌妻。代乃。不過現(xiàn)在還好累铅,已經(jīng)定下來啦大家都使用的一個東西 脫水:服務(wù)員颈渊,我要的是13歲的噢→_→

然后服務(wù)器會返回下列東西班缎,表示已經(jīng)接受到請求寓娩, 成功建立Websocket啦!

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

這里開始就是HTTP最后負(fù)責(zé)的區(qū)域了堕仔,告訴客戶擂橘,我已經(jīng)成功切換協(xié)議啦~

Upgrade: websocket
Connection: Upgrade

依然是固定的,告訴客戶端即將升級的是Websocket協(xié)議摩骨,而不是mozillasocket通贞,lurnarsocket或者shitsocket。
然后仿吞,Sec-WebSocket-Accept 這個則是經(jīng)過服務(wù)器確認(rèn)滑频,并且加密過后的 Sec-WebSocket-Key。服務(wù)器:好啦好啦唤冈,知道啦,給你看我的ID CARD來證明行了吧银伟。你虹。
后面的,Sec-WebSocket-Protocol 則是表示最終使用的協(xié)議彤避。

至此傅物,HTTP已經(jīng)完成它所有工作了,接下來就是完全按照Websocket協(xié)議進(jìn)行了琉预。
具體的協(xié)議就不在這闡述了董饰。
------------------技術(shù)解析部分完畢------------------

image

你TMD又BBB了這么久,那到底Websocket有什么鬼用圆米,http long poll卒暂,或者ajax輪詢不都可以實現(xiàn)實時信息傳遞么。

image

好好好娄帖,年輕人也祠,那我們來講一講Websocket有什么用。
來給你吃點胡(蘇)蘿(丹)卜(紅)

<noscript>
image

三近速、Websocket的作用
在講Websocket之前诈嘿,我就順帶著講下 long poll 和 ajax輪詢 的原理。
首先是 ajax輪詢 削葱,ajax輪詢 的原理非常簡單奖亚,讓瀏覽器隔個幾秒就發(fā)送一次請求,詢問服務(wù)器是否有新信息析砸。
場景再現(xiàn):
客戶端:啦啦啦昔字,有沒有新信息(Request)
服務(wù)端:沒有(Response)
客戶端:啦啦啦,有沒有新信息(Request)
服務(wù)端:沒有干厚。李滴。(Response)
客戶端:啦啦啦螃宙,有沒有新信息(Request)
服務(wù)端:你好煩啊,沒有啊所坯。谆扎。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務(wù)端:好啦好啦芹助,有啦給你堂湖。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務(wù)端:状土。无蜂。。蒙谓。斥季。沒。累驮。酣倾。。沒谤专。躁锡。。沒有(Response) ---- loop

long poll
long poll 其實原理跟 ajax輪詢 差不多置侍,都是采用輪詢的方式映之,不過采取的是阻塞模型(一直打電話,沒收到就不掛電話)蜡坊,也就是說杠输,客戶端發(fā)起連接后,如果沒消息算色,就一直不返回Response給客戶端抬伺。直到有消息才返回,返回完之后灾梦,客戶端再次建立連接峡钓,周而復(fù)始。
場景再現(xiàn)
客戶端:啦啦啦若河,有沒有新信息能岩,沒有的話就等有了才返回給我吧(Request)
服務(wù)端:額。萧福。 等待到有消息的時候拉鹃。。來 給你(Response)
客戶端:啦啦啦,有沒有新信息膏燕,沒有的話就等有了才返回給我吧(Request) -loop

從上面可以看出其實這兩種方式钥屈,都是在不斷地建立HTTP連接,然后等待服務(wù)端處理坝辫,可以體現(xiàn)HTTP協(xié)議的另外一個特點篷就,被動性
何為被動性呢近忙,其實就是竭业,服務(wù)端不能主動聯(lián)系客戶端,只能有客戶端發(fā)起及舍。
簡單地說就是未辆,服務(wù)器是一個很懶的冰箱(這是個梗)(不會、不能主動發(fā)起連接)锯玛,但是上司有命令咐柜,如果有客戶來,不管多么累都要好好接待攘残。

說完這個炕桨,我們再來說一說上面的缺陷(原諒我廢話這么多吧OAQ)
從上面很容易看出來,不管怎么樣肯腕,上面這兩種都是非常消耗資源的。
ajax輪詢 需要服務(wù)器有很快的處理速度和資源钥平。(速度)
long poll 需要有很高的并發(fā)实撒,也就是說同時接待客戶的能力。(場地大猩骜)
所以ajax輪詢 和long poll 都有可能發(fā)生這種情況知态。

客戶端:啦啦啦啦,有新信息么立叛?
服務(wù)端:月線正忙负敏,請稍后再試(503 Server Unavailable)
客戶端:。秘蛇。其做。。好吧赁还,啦啦啦妖泄,有新信息么?
服務(wù)端:月線正忙艘策,請稍后再試(503 Server Unavailable)
客戶端:

image

然后服務(wù)端在一旁忙的要死:冰箱蹈胡,我要更多的冰箱!更多。罚渐。更多却汉。。(我錯了荷并。合砂。這又是梗。璧坟。)


言歸正傳既穆,我們來說Websocket吧
通過上面這個例子,我們可以看出雀鹃,這兩種方式都不是最好的方式幻工,需要很多資源。
一種需要更快的速度黎茎,一種需要更多的'電話'囊颅。這兩種都會導(dǎo)致'電話'的需求越來越高。
哦對了傅瞻,忘記說了HTTP還是一個無狀態(tài)協(xié)議踢代。(感謝評論區(qū)的各位指出OAQ)
通俗的說就是,服務(wù)器因為每天要接待太多客戶了嗅骄,是個健忘鬼胳挎,你一掛電話,他就把你的東西全忘光了溺森,把你的東西全丟掉了慕爬。你第二次還得再告訴服務(wù)器一遍。

所以在這種情況下出現(xiàn)了屏积,Websocket出現(xiàn)了医窿。
他解決了HTTP的這幾個難題。
首先炊林,被動性姥卢,當(dāng)服務(wù)器完成協(xié)議升級后(HTTP->Websocket),服務(wù)端就可以主動推送信息給客戶端啦渣聚。
所以上面的情景可以做如下修改独榴。
客戶端:啦啦啦,我要建立Websocket協(xié)議饵逐,需要的服務(wù):chat括眠,Websocket協(xié)議版本:17(HTTP Request)
服務(wù)端:ok,確認(rèn)倍权,已升級為Websocket協(xié)議(HTTP Protocols Switched)
客戶端:麻煩你有信息的時候推送給我噢掷豺。捞烟。
服務(wù)端:ok,有的時候會告訴你的当船。
服務(wù)端:balabalabalabala
服務(wù)端:balabalabalabala
服務(wù)端:哈哈哈哈哈啊哈哈哈哈
服務(wù)端:笑死我了哈哈哈哈哈哈哈

就變成了這樣题画,只需要經(jīng)過一次HTTP請求,就可以做到源源不斷的信息傳送了德频。(在程序設(shè)計中苍息,這種設(shè)計叫做回調(diào),即:你有信息了再來通知我壹置,而不是我傻乎乎的每次跑來問你)
這樣的協(xié)議解決了上面同步有延遲竞思,而且還非常消耗資源的這種情況。
那么為什么他會解決服務(wù)器上消耗資源的問題呢钞护?
其實我們所用的程序是要經(jīng)過兩層代理的盖喷,即HTTP協(xié)議在Nginx等服務(wù)器的解析下,然后再傳送給相應(yīng)的Handler(PHP等)來處理难咕。
簡單地說课梳,我們有一個非常快速的接線員(Nginx)余佃,他負(fù)責(zé)把問題轉(zhuǎn)交給相應(yīng)的客服(Handler)暮刃。
本身接線員基本上速度是足夠的,但是每次都卡在客服(Handler)了爆土,老有客服處理速度太慢椭懊。,導(dǎo)致客服不夠步势。
Websocket就解決了這樣一個難題灾搏,建立后,可以直接跟接線員建立持久連接立润,有信息的時候客服想辦法通知接線員,然后接線員在統(tǒng)一轉(zhuǎn)交給客戶媳板。
這樣就可以解決客服處理速度過慢的問題了桑腮。

同時,在傳統(tǒng)的方式上蛉幸,要不斷的建立破讨,關(guān)閉HTTP協(xié)議,由于HTTP是非狀態(tài)性的奕纫,每次都要重新傳輸identity info(鑒別信息)提陶,來告訴服務(wù)端你是誰。
雖然接線員很快速匹层,但是每次都要聽這么一堆隙笆,效率也會有所下降的锌蓄,同時還得不斷把這些信息轉(zhuǎn)交給客服,不但浪費客服的處理時間撑柔,而且還會在網(wǎng)路傳輸中消耗過多的流量/時間瘸爽。
但是Websocket只需要一次HTTP握手,所以說整個通訊過程是建立在一次連接/狀態(tài)中铅忿,也就避免了HTTP的非狀態(tài)性剪决,服務(wù)端會一直知道你的信息,直到你關(guān)閉請求檀训,這樣就解決了接線員要反復(fù)解析HTTP協(xié)議柑潦,還要查看identity info的信息。
同時由客戶主動詢問峻凫,轉(zhuǎn)換為服務(wù)器(推送)有信息的時候就發(fā)送(當(dāng)然客戶端還是等主動發(fā)送信息過來的渗鬼。。)蔚晨,沒有信息的時候就交給接線員(Nginx)乍钻,不需要占用本身速度就慢的客服(Handler)


至于怎么在不支持Websocket的客戶端上使用Websocket。铭腕。答案是:不能
但是可以通過上面說的 long poll 和 ajax 輪詢來 模擬出類似的效果

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末银择,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子累舷,更是在濱河造成了極大的恐慌浩考,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件被盈,死亡現(xiàn)場離奇詭異析孽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)只怎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門袜瞬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人身堡,你說我怎么就攤上這事邓尤。” “怎么了贴谎?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵汞扎,是天一觀的道長。 經(jīng)常有香客問我擅这,道長澈魄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任仲翎,我火速辦了婚禮痹扇,結(jié)果婚禮上铛漓,老公的妹妹穿的比我還像新娘。我一直安慰自己帘营,他們只是感情好票渠,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芬迄,像睡著了一般问顷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上禀梳,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天杜窄,我揣著相機(jī)與錄音,去河邊找鬼算途。 笑死塞耕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嘴瓤。 我是一名探鬼主播扫外,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼廓脆!你這毒婦竟也來了筛谚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤停忿,失蹤者是張志新(化名)和其女友劉穎驾讲,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體席赂,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡吮铭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了颅停。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谓晌。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖癞揉,靈堂內(nèi)的尸體忽然破棺而出扎谎,到底是詐尸還是另有隱情,我是刑警寧澤烧董,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站胧奔,受9級特大地震影響逊移,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜龙填,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一胳泉、第九天 我趴在偏房一處隱蔽的房頂上張望拐叉。 院中可真熱鬧,春花似錦扇商、人聲如沸凤瘦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔬芥。三九已至,卻和暖如春控汉,著一層夾襖步出監(jiān)牢的瞬間笔诵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工姑子, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留乎婿,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓街佑,卻偏偏與公主長得像谢翎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子沐旨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容