websocket出現(xiàn)的背景
Web應(yīng)用的通信過(guò)程通常是客戶(hù)端通過(guò)瀏覽器發(fā)出一個(gè)請(qǐng)求举庶,服務(wù)器端接收請(qǐng)求后進(jìn)行處理并返回結(jié)果給客戶(hù)端,客戶(hù)端瀏覽器將信息呈現(xiàn)义图。這種機(jī)制對(duì)于信息變化不是特別頻繁的應(yīng)用可以良好支撐棺滞,但對(duì)于實(shí)時(shí)要求高、海量并發(fā)的應(yīng)用來(lái)說(shuō)顯得捉襟見(jiàn)肘卵史,尤其在當(dāng)前業(yè)界移動(dòng)互聯(lián)網(wǎng)蓬勃發(fā)展的趨勢(shì)下,高并發(fā)與用戶(hù)實(shí)時(shí)響應(yīng)是Web應(yīng)用經(jīng)常面臨的問(wèn)題搜立,比如金融證券的實(shí)時(shí)信息以躯、Web導(dǎo)航應(yīng)用中的地理位置獲取、社交網(wǎng)絡(luò)的實(shí)時(shí)消息推送等啄踊。
傳統(tǒng)的請(qǐng)求-響應(yīng)模式的Web開(kāi)發(fā)在處理此類(lèi)業(yè)務(wù)場(chǎng)景時(shí)忧设,通常采用實(shí)時(shí)通訊方案。傳統(tǒng)HTTP每次請(qǐng)求-應(yīng)答都需要客戶(hù)端與服務(wù)端建立連接的模式颠通,比如常見(jiàn)的輪詢(xún)方案址晕,http long poll,ajax輪詢(xún)顿锰。
當(dāng)客戶(hù)端以固定頻率向服務(wù)器端發(fā)送請(qǐng)求時(shí)谨垃,服務(wù)器端的數(shù)據(jù)可能并沒(méi)有更新,帶來(lái)很多無(wú)謂請(qǐng)求撵儿,浪費(fèi)帶寬乘客,效率低下狐血。傳統(tǒng)的Web模式在處理高并發(fā)及實(shí)時(shí)性需求的時(shí)候淀歇,會(huì)遇到難以逾越的瓶頸,需要一種高效節(jié)能的雙向通信機(jī)制來(lái)保證數(shù)據(jù)的實(shí)時(shí)傳輸匈织。在此背景下浪默,基于HTML5規(guī)范的、有Web TCP之稱(chēng)的 WebSocket應(yīng)運(yùn)而生缀匕。
那么纳决,什么是websocket?
知乎上看到一篇文章講的很明白很萌~
websocket和HTML5乡小、HTTP的關(guān)系阔加?
WebSocket是HTML5出的東西(協(xié)議),也就是說(shuō)HTTP協(xié)議沒(méi)有變化满钟,或者說(shuō)沒(méi)關(guān)系胜榔,但HTTP是不支持持久連接的(長(zhǎng)連接胳喷,循環(huán)連接的不算)首先HTTP有1.1和1.0之說(shuō),也就是所謂的keep-alive夭织,把多個(gè)HTTP請(qǐng)求合并為一個(gè)吭露,但是Websocket其實(shí)是一個(gè)新協(xié)議,跟HTTP協(xié)議基本沒(méi)有關(guān)系尊惰,只是為了兼容現(xiàn)有瀏覽器的握手規(guī)范而已讲竿,也就是說(shuō)它是HTTP協(xié)議上的一種補(bǔ)充。一弄屡、有交集题禀,但是并不是全部。另外Html5是指的一系列新的API琢岩,或者說(shuō)新規(guī)范投剥,新技術(shù)。Http協(xié)議本身只有1.0和1.1担孔,而且跟Html本身沒(méi)有直接關(guān)系江锨。通俗來(lái)說(shuō),你可以用HTTP協(xié)議傳輸非Html數(shù)據(jù)糕篇。
Websocket是什么樣的協(xié)議啄育?
Websocket是一個(gè)持久化的協(xié)議,相對(duì)于HTTP這種非持久的協(xié)議來(lái)說(shuō)拌消。
用目前應(yīng)用比較廣泛的PHP生命周期來(lái)解釋挑豌。
- HTTP的生命周期通過(guò)Request來(lái)界定,也就是一個(gè)Request 一個(gè)Response墩崩,那么在HTTP1.0中氓英,這次HTTP請(qǐng)求就結(jié)束了。在HTTP1.1中進(jìn)行了改進(jìn)鹦筹,使得有一個(gè)keep-alive铝阐,也就是說(shuō),在一個(gè)HTTP連接中铐拐,可以發(fā)送多個(gè)Request徘键,接收多個(gè)Response。但是請(qǐng)記住 Request = Response 遍蟋, 在HTTP中永遠(yuǎn)是這樣吹害,也就是說(shuō)一個(gè)request只能有一個(gè)response。而且這個(gè)response也是被動(dòng)的虚青,不能主動(dòng)發(fā)起它呀。
Websocket是基于HTTP協(xié)議的,或者說(shuō)借用了HTTP的協(xié)議來(lái)完成一部分握手。在握手階段是一樣的纵穿。
- 一個(gè)典型的Websocket握手
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
這段類(lèi)似HTTP協(xié)議的握手請(qǐng)求中烟号,多了幾個(gè)東西。
Upgrade: websocket
Connection: Upgrade
這個(gè)就是Websocket的核心了政恍,告訴Apache汪拥、Nginx等服務(wù)器:注意啦,我發(fā)起的是Websocket協(xié)議篙耗,快點(diǎn)幫我找到對(duì)應(yīng)的助理處理~不是那個(gè)老土的HTTP迫筑。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Sec-WebSocket-Key
是一個(gè)Base64 encode的值,這個(gè)是瀏覽器隨機(jī)生成的宗弯,告訴服務(wù)器,我要驗(yàn)證尼是不是真的是Websocket助理脯燃。
Sec_WebSocket-Protocol
是一個(gè)用戶(hù)定義的字符串,用來(lái)區(qū)分同URL下蒙保,不同的服務(wù)所需要的協(xié)議辕棚。
Sec-WebSocket-Version
是告訴服務(wù)器所使用的Websocket Draft(協(xié)議版本),
在最初的時(shí)候,Websocket協(xié)議還在 Draft 階段邓厕,各種奇奇怪怪的協(xié)議都有逝嚎,而且還有很多奇奇怪怪不同的東西,什么Firefox和Chrome用的不是一個(gè)版本之類(lèi)的详恼,當(dāng)初Websocket協(xié)議太多.可是一個(gè)大難題,不過(guò)現(xiàn)在還好补君,已經(jīng)定下來(lái)啦,大家都使用的一個(gè)東西。然后服務(wù)器會(huì)返回下列東西昧互,表示已經(jīng)接受到請(qǐng)求挽铁,成功建立Websocket啦!
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
這里開(kāi)始就是HTTP最后負(fù)責(zé)的區(qū)域了敞掘,告訴客戶(hù)叽掘,我已經(jīng)成功切換協(xié)議啦~
Upgrade: websocket
Connection: Upgrade
依然是固定的,告訴客戶(hù)端即將升級(jí)的是Websocket協(xié)議玖雁,而不是mozillasocket更扁,lurnarsocket或者shitsocket。然后茄菊,Sec-WebSocket-Accept 這個(gè)則是經(jīng)過(guò)服務(wù)器確認(rèn)疯潭,并且加密過(guò)后的 Sec-WebSocket-Key赊堪。服務(wù)器:好啦好啦面殖,知道啦,給你看我的ID CARD來(lái)證明行了吧哭廉。脊僚。后面的,Sec-WebSocket-Protocol 則是表示最終使用的協(xié)議。至此辽幌,HTTP已經(jīng)完成它所有工作了增淹,接下來(lái)就是完全按照Websocket協(xié)議進(jìn)行了。具體的協(xié)議就不在這闡述了乌企。
具體有什么優(yōu)點(diǎn)?
http long poll虑润,或者ajax輪詢(xún)不都可以實(shí)現(xiàn)實(shí)時(shí)信息傳遞么?Websocket具有什么優(yōu)點(diǎn)加酵?
ajax輪詢(xún)的原理:讓瀏覽器隔個(gè)幾秒就發(fā)送一次請(qǐng)求拳喻,詢(xún)問(wèn)服務(wù)器是否有新信息。若沒(méi)有猪腕,服務(wù)器回復(fù)response沒(méi)有新信息冗澈,結(jié)束本次請(qǐng)求,瀏覽器繼續(xù)發(fā)送新的請(qǐng)求陋葡,如此循環(huán)亚亲。
場(chǎng)景再現(xiàn):
客戶(hù)端:啦啦啦,有沒(méi)有新信息(Request)
服務(wù)端:沒(méi)有(Response)
客戶(hù)端:啦啦啦腐缤,有沒(méi)有新信息(Request)
服務(wù)端:沒(méi)有捌归。。(Response)
客戶(hù)端:啦啦啦岭粤,有沒(méi)有新信息(Request)
服務(wù)端:你好煩啊陨溅,沒(méi)有啊。绍在。(Response)
客戶(hù)端:啦啦啦门扇,有沒(méi)有新消息(Request)
服務(wù)端:好啦好啦,有啦給你偿渡。(Response)
客戶(hù)端:啦啦啦臼寄,有沒(méi)有新消息(Request)
服務(wù)端:。溜宽。吉拳。。适揉。沒(méi)留攒。。嫉嘀。炼邀。沒(méi)。剪侮。拭宁。沒(méi)有(Response) ---- loop
long poll long poll 其實(shí)原理跟 ajax輪詢(xún) 差不多,都是采用輪詢(xún)的方式,不過(guò)采取的是阻塞模型(一直打電話杰标,沒(méi)收到就不掛電話)兵怯,也就是說(shuō),客戶(hù)端發(fā)起連接后腔剂,如果沒(méi)消息媒区,就一直不返回Response給客戶(hù)端。直到有消息才返回掸犬,返回完之后驻仅,客戶(hù)端再次建立連接,周而復(fù)始登渣。
場(chǎng)景再現(xiàn)
客戶(hù)端:啦啦啦噪服,有沒(méi)有新信息,沒(méi)有的話就等有了才返回給我吧(Request)
服務(wù)端:額胜茧。粘优。 等待到有消息的時(shí)候。呻顽。來(lái) 給你(Response)
客戶(hù)端:啦啦啦雹顺,有沒(méi)有新信息,沒(méi)有的話就等有了才返回給我吧(Request)
-loop
從上面可以看出其實(shí)這兩種方式廊遍,都是在不斷地建立HTTP連接嬉愧,然后等待服務(wù)端處理,可以體現(xiàn)HTTP協(xié)議的另外一個(gè)特點(diǎn)喉前,被動(dòng)性没酣。何為被動(dòng)性呢,其實(shí)就是卵迂,服務(wù)端不能主動(dòng)聯(lián)系客戶(hù)端裕便,只能有客戶(hù)端發(fā)起。簡(jiǎn)單地說(shuō)就是见咒,服務(wù)器是一個(gè)很懶(不會(huì)偿衰、不能主動(dòng)發(fā)起連接),但是上司有命令改览,如果有客戶(hù)來(lái)下翎,不管多么累都要好好接待。
上面這兩種都是非常消耗資源的宝当。ajax輪詢(xún) 需要服務(wù)器有很快的處理速度和資源视事。(速度)long poll 需要有很高的并發(fā),也就是說(shuō)同時(shí)接待客戶(hù)的能力今妄。
所以ajax輪詢(xún) 和long poll 都有可能發(fā)生這種情況郑口。
客戶(hù)端:啦啦啦啦,有新信息么盾鳞?
服務(wù)端:月線正忙犬性,請(qǐng)稍后再試(503 Server Unavailable)
客戶(hù)端:。腾仅。乒裆。。好吧推励,啦啦啦鹤耍,有新信息么?
服務(wù)端:月線正忙验辞,請(qǐng)稍后再試(503 Server Unavailable)
然后服務(wù)端在一旁忙的要死
這兩種方式都不是最好的方式稿黄,需要很多資源。一種需要更快的速度跌造,一種需要更多的'電話'杆怕。這兩種都會(huì)導(dǎo)致'電話'的需求越來(lái)越高。
HTTP還是一個(gè)無(wú)狀態(tài)協(xié)議壳贪。通俗的說(shuō)就是陵珍,服務(wù)器因?yàn)槊刻煲哟嗫蛻?hù)了,是個(gè)健忘鬼违施,你一掛電話互纯,他就把你的東西全忘光了,把你的東西全丟掉了磕蒲。你第二次還得再告訴服務(wù)器一遍留潦。所以在這種情況下出現(xiàn)了,Websocket出現(xiàn)了辣往。他解決了HTTP的這幾個(gè)難題愤兵。首先,被動(dòng)性排吴,當(dāng)服務(wù)器完成協(xié)議升級(jí)后(HTTP->Websocket)秆乳,服務(wù)端就可以主動(dòng)推送信息給客戶(hù)端啦。
客戶(hù)端:啦啦啦钻哩,我要建立Websocket協(xié)議屹堰,需要的服務(wù):chat,Websocket協(xié)議版本:17(HTTP Request)
服務(wù)端:ok街氢,確認(rèn)扯键,已升級(jí)為Websocket協(xié)議(HTTP Protocols Switched)
客戶(hù)端:麻煩你有信息的時(shí)候推送給我噢。珊肃。服務(wù)端:ok荣刑,有的時(shí)候會(huì)告訴你的馅笙。
服務(wù)端:balabalabalabala
服務(wù)端:balabalabalabala
服務(wù)端:哈哈哈哈哈啊哈哈哈哈
服務(wù)端:笑死我了哈哈哈哈哈哈哈
就變成了這樣,只需要經(jīng)過(guò)一次HTTP請(qǐng)求厉亏,就可以做到源源不斷的信息傳送了董习。(在程序設(shè)計(jì)中,這種設(shè)計(jì)叫做回調(diào)爱只,即:你有信息了再來(lái)通知我皿淋,而不是我傻乎乎的每次跑來(lái)問(wèn)你)
這樣的協(xié)議解決了上面同步有延遲,而且還非常消耗資源的這種情況恬试。
那么為什么他會(huì)解決服務(wù)器上消耗資源的問(wèn)題呢窝趣?其實(shí)我們所用的程序是要經(jīng)過(guò)兩層代理的,即HTTP協(xié)議在Nginx等服務(wù)器的解析下训柴,然后再傳送給相應(yīng)的Handler(PHP等)來(lái)處理哑舒。簡(jiǎn)單地說(shuō),我們有一個(gè)非郴媚伲快速的接線員(Nginx)散址,他負(fù)責(zé)把問(wèn)題轉(zhuǎn)交給相應(yīng)的客服(Handler)。本身接線員基本上速度是足夠的宣赔,但是每次都卡在客服(Handler)了预麸,老有客服處理速度太慢。儒将,導(dǎo)致客服不夠吏祸。Websocket就解決了這樣一個(gè)難題,建立后钩蚊,可以直接跟接線員建立持久連接贡翘,有信息的時(shí)候客服想辦法通知接線員,然后接線員在統(tǒng)一轉(zhuǎn)交給客戶(hù)砰逻。這樣就可以解決客服處理速度過(guò)慢的問(wèn)題了鸣驱。
同時(shí),在傳統(tǒng)的方式上蝠咆,要不斷的建立踊东,關(guān)閉HTTP協(xié)議,由于HTTP是非狀態(tài)性的刚操,每次都要重新傳輸identity info(鑒別信息)闸翅,來(lái)告訴服務(wù)端你是誰(shuí)。雖然接線員很快速菊霜,但是每次都要聽(tīng)這么一堆坚冀,效率也會(huì)有所下降的,同時(shí)還得不斷把這些信息轉(zhuǎn)交給客服鉴逞,不但浪費(fèi)客服的處理時(shí)間记某,而且還會(huì)在網(wǎng)路傳輸中消耗過(guò)多的流量/時(shí)間司训。
但是Websocket只需要一次HTTP握手,所以說(shuō)整個(gè)通訊過(guò)程是建立在一次連接/狀態(tài)中液南,也就避免了HTTP的非狀態(tài)性壳猜,服務(wù)端會(huì)一直知道你的信息,直到你關(guān)閉請(qǐng)求贺拣,這樣就解決了接線員要反復(fù)解析HTTP協(xié)議蓖谢,還要查看identity info的信息捂蕴。同時(shí)由客戶(hù)主動(dòng)詢(xún)問(wèn)譬涡,轉(zhuǎn)換為服務(wù)器(推送)有信息的時(shí)候就發(fā)送(當(dāng)然客戶(hù)端還是等主動(dòng)發(fā)送信息過(guò)來(lái)的。啥辨。)涡匀,沒(méi)有信息的時(shí)候就交給接線員(Nginx),不需要占用本身速度就慢的客服(Handler)了
作者:Ovear
鏈接:https://www.zhihu.com/question/20215561/answer/40316953
關(guān)于http的閱讀 http
有關(guān)聊天室的實(shí)現(xiàn)步驟溉知,以后有時(shí)間再寫(xiě)陨瘩。
我是參考慕課網(wǎng)上的教程寫(xiě)了一個(gè)。
代碼地址