先粘貼上一個知乎回帖捐晶,說的很清晰伸刃,語言也萌萌噠 看完會感覺豁然開朗拢军,下面是正文:
一、websocket與http
WebSocket是HTML5出的東西(協(xié)議)送巡,也就是說HTTP協(xié)議沒有變化摹菠,或者說沒關系,但HTTP是不支持持久連接的(長連接骗爆,循環(huán)連接的不算)
首先HTTP有1.1和1.0之說次氨,也就是所謂的keep-alive,把多個HTTP請求合并為一個摘投,但是Websocket其實是一個新協(xié)議煮寡,跟HTTP協(xié)議基本沒有關系,只是為了兼容現有瀏覽器的握手規(guī)范而已犀呼,也就是說它是HTTP協(xié)議上的一種補充可以通過這樣一張圖理解
有交集幸撕,但是并不是全部。
另外html5是指的一系列新的API外臂,或者說新規(guī)范坐儿,新技術。Http協(xié)議本身只有1.0和1.1宋光,而且跟Html本身沒有直接關系貌矿。。通俗來說罪佳,你可以用HTTP協(xié)議傳輸非Html數據逛漫,就是這樣=。=
再簡單來說赘艳,層級不一樣酌毡。
二、Websocket是什么樣的協(xié)議第练,具體有什么優(yōu)點
首先阔馋,Websocket是一個持久化的協(xié)議玛荞,相對于HTTP這種非持久的協(xié)議來說娇掏。簡單的舉個例子吧,用目前應用比較廣泛的PHP生命周期來解釋勋眯。
HTTP的生命周期通過Request來界定婴梧,也就是一個Request一個Response下梢,那么在HTTP1.0中,這次HTTP請求就結束了塞蹭。
在HTTP1.1中進行了改進孽江,使得有一個keep-alive,也就是說番电,在一個HTTP連接中岗屏,可以發(fā)送多個Request,接收多個Response漱办。但是請記住Request = Response这刷, 在HTTP中永遠是這樣,也就是說一個request只能有一個response娩井。而且這個response也是被動的暇屋,不能主動發(fā)起。
教練洞辣,你BB了這么多咐刨,跟Websocket有什么關系呢?_(:з」∠)_好吧扬霜,我正準備說Websocket呢定鸟。。
首先Websocket是基于HTTP協(xié)議的著瓶,或者說借用了HTTP的協(xié)議來完成一部分握手仔粥。
首先我們來看個典型的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ā)現了躯泰,這段類似HTTP協(xié)議的握手請求中,多了幾個東西华糖。我會順便講解下作用麦向。
Upgrade: websocket
Connection: Upgrade
這個就是Websocket的核心了,告訴Apache客叉、Nginx等服務器:注意啦诵竭,我發(fā)起的是Websocket協(xié)議,快點幫我找到對應的助理處理~不是那個老土的HTTP兼搏。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
首先卵慰,Sec-WebSocket-Key是一個Base64 encode的值,這個是瀏覽器隨機生成的佛呻,告訴服務器:泥煤裳朋,不要忽悠窩,我要驗證尼是不是真的是Websocket助理吓著。
然后鲤嫡,Sec_WebSocket-Protocol是一個用戶定義的字符串送挑,用來區(qū)分同URL下,不同的服務所需要的協(xié)議暖眼。簡單理解:今晚我要服務A惕耕,別搞錯啦~
最后,Sec-WebSocket-Version是告訴服務器所使用的Websocket Draft(協(xié)議版本)诫肠,在最初的時候司澎,Websocket協(xié)議還在Draft階段,各種奇奇怪怪的協(xié)議都有栋豫,而且還有很多期奇奇怪怪不同的東西惭缰,什么Firefox和Chrome用的不是一個版本之類的,當初Websocket協(xié)議太多可是一個大難題笼才。漱受。不過現在還好,已經定下來啦~大家都使用的一個東西~ 脫水:服務員骡送,我要的是13歲的噢→_→
然后服務器會返回下列東西昂羡,表示已經接受到請求, 成功建立Websocket啦摔踱!
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
這里開始就是HTTP最后負責的區(qū)域了虐先,告訴客戶,我已經成功切換協(xié)議啦~
Upgrade: websocket
Connection: Upgrade
依然是固定的派敷,告訴客戶端即將升級的是Websocket協(xié)議蛹批,而不是mozillasocket,lurnarsocket或者shitsocket篮愉。
然后腐芍,Sec-WebSocket-Accept這個則是經過服務器確認,并且加密過后的Sec-WebSocket-Key试躏。?服務器:好啦好啦猪勇,知道啦,給你看我的ID CARD來證明行了吧颠蕴。泣刹。
后面的,Sec-WebSocket-Protocol則是表示最終使用的協(xié)議犀被。
至此椅您,HTTP已經完成它所有工作了,接下來就是完全按照Websocket協(xié)議進行了寡键。具體的協(xié)議就不在這闡述了掀泳。
——————技術解析部分完畢——————
你TMD又BBB了這么久,那到底Websocket有什么鬼用,http long poll开伏,或者ajax輪詢不都可以實現實時信息傳遞么膀跌。
好好好遭商,年輕人固灵,那我們來講一講Websocket有什么用。來給你吃點胡(蘇)蘿(丹)卜(紅)
在講Websocket之前巫玻,我就順帶著講下long poll和ajax輪詢的原理。
ajax輪詢的原理非常簡單祠汇,讓瀏覽器隔個幾秒就發(fā)送一次請求仍秤,詢問服務器是否有新信息。
場景再現:
客戶端:啦啦啦可很,有沒有新信息(Request)
服務端:沒有(Response)
客戶端:啦啦啦诗力,有沒有新信息(Request)
服務端:沒有。我抠。(Response)
客戶端:啦啦啦苇本,有沒有新信息(Request)
服務端:你好煩啊,沒有啊菜拓。瓣窄。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務端:好啦好啦纳鼎,有啦給你俺夕。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務端:贱鄙。劝贸。。逗宁。悬荣。沒。疙剑。氯迂。。沒言缤。嚼蚀。。沒有(Response) —- loop
long poll其實原理跟ajax輪詢差不多管挟,都是采用輪詢的方式轿曙,不過采取的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說导帝,客戶端發(fā)起連接后守谓,如果沒消息,就一直不返回Response給客戶端您单。直到有消息才返回斋荞,返回完之后,客戶端再次建立連接虐秦,周而復始平酿。
場景再現:
客戶端:啦啦啦,有沒有新信息悦陋,沒有的話就等有了才返回給我吧(Request)
服務端:額蜈彼。。 等待到有消息的時候俺驶。幸逆。來 給你(Response)
客戶端:啦啦啦,有沒有新信息暮现,沒有的話就等有了才返回給我吧(Request) -loop
從上面可以看出其實這兩種方式还绘,都是在不斷地建立HTTP連接,然后等待服務端處理送矩,可以體現HTTP協(xié)議的另外一個特點蚕甥,被動性。
何為被動性呢栋荸,其實就是菇怀,服務端不能主動聯(lián)系客戶端,只能有客戶端發(fā)起晌块。
簡單地說就是爱沟,服務器是一個很懶的冰箱(這是個梗)(不會、不能主動發(fā)起連接)匆背,但是上司有命令呼伸,如果有客戶來,不管多么累都要好好接待钝尸。
說完這個括享,我們再來說一說上面的缺陷(原諒我廢話這么多吧OAQ)
從上面很容易看出來,不管怎么樣珍促,上面這兩種都是非常消耗資源的铃辖。
ajax輪詢 需要服務器有很快的處理速度和資源。(速度)long poll 需要有很高的并發(fā)猪叙,也就是說同時接待客戶的能力娇斩。(場地大腥示怼)
所以ajax輪詢和long poll都有可能發(fā)生這種情況。
客戶端:啦啦啦啦犬第,有新信息么锦积?
服務端:月線正忙,請稍后再試(503 Server Unavailable)
客戶端:歉嗓。丰介。。遥椿。好吧基矮,啦啦啦淆储,有新信息么冠场?
服務端:月線正忙,請稍后再試(503 Server Unavailable)
客戶端:然后服務端在一旁忙的要死:冰箱本砰,我要更多的冰箱碴裙!更多点额。。更多还棱。。(我錯了珍手。办铡。這又是梗。琳要。)
通過上面這個例子稚补,我們可以看出,這兩種方式都不是最好的方式课幕,需要很多資源厦坛。
一種需要更快的速度,一種需要更多的’電話’乍惊。這兩種都會導致’電話’的需求越來越高。
哦對了污桦,忘記說了HTTP還是一個狀態(tài)協(xié)議匙监。
通俗的說就是小作,服務器因為每天要接待太多客戶了,是個健忘鬼顾稀,你一掛電話,他就把你的東西全忘光了静秆,把你的東西全丟掉了。你第二次還得再告訴服務器一遍抚笔。
所以在這種情況下出現了,Websocket出現了辐宾。他解決了HTTP的這幾個難題膨蛮。首先,被動性敞葛,當服務器完成協(xié)議升級后(HTTP->Websocket),服務端就可以主動推送信息給客戶端啦惹谐。所以上面的情景可以做如下修改。
客戶端:啦啦啦综液,我要建立Websocket協(xié)議儒飒,需要的服務:chat,Websocket協(xié)議版本:17(HTTP Request)
服務端:ok桩了,確認附帽,已升級為Websocket協(xié)議(HTTP Protocols Switched)
客戶端:麻煩你有信息的時候推送給我噢。井誉。
服務端:ok,有的時候會告訴你的颗圣。
服務端:balabalabalabala
服務端:balabalabalabala
服務端:哈哈哈哈哈啊哈哈哈哈
服務端:笑死我了哈哈哈哈哈哈哈
就變成了這樣屁使,只需要經過一次HTTP請求奔则,就可以做到源源不斷的信息傳送了。(在程序設計中酬蹋,這種設計叫做回調抽莱,即:你有信息了再來通知我范抓,而不是我傻乎乎的每次跑來問你?)
這樣的協(xié)議解決了上面同步有延遲食铐,而且還非常消耗資源的這種情況。那么為什么他會解決服務器上消耗資源的問題呢年缎?
其實我們所用的程序是要經過兩層代理的铃慷,即HTTP協(xié)議在Nginx等服務器的解析下蜕该,然后再傳送給相應的Handler(php等)來處理。簡單地說堂淡,我們有一個非常快速的接線員(Nginx)萤悴,他負責把問題轉交給相應的客服(Handler)皆的。
本身接線員基本上速度是足夠的,但是每次都卡在客服(Handler)了费薄,老有客服處理速度太慢。伟众,導致客服不夠召廷。Websocket就解決了這樣一個難題账胧,建立后先紫,可以直接跟接線員建立持久連接,有信息的時候客服想辦法通知接線員泡孩,然后接線員在統(tǒng)一轉交給客戶。
這樣就可以解決客服處理速度過慢的問題了吮播。
同時眼俊,在傳統(tǒng)的方式上,要不斷的建立疮胖,關閉HTTP協(xié)議,由于HTTP是非狀態(tài)性的院塞,每次都要重新傳輸identity info(鑒別信息)性昭,來告訴服務端你是誰。
雖然接線員很快速糜颠,但是每次都要聽這么一堆,效率也會有所下降的顶瞒,同時還得不斷把這些信息轉交給客服元旬,不但浪費客服的處理時間,而且還會在網路傳輸中消耗過多的流量/時間法绵。
但是Websocket只需要一次HTTP握手青责,所以說整個通訊過程是建立在一次連接/狀態(tài)中肤视,也就避免了HTTP的非狀態(tài)性字柠,服務端會一直知道你的信息窑业,直到你關閉請求,這樣就解決了接線員要反復解析HTTP協(xié)議鲤氢,還要查看identity info的信息西潘。
同時由客戶主動詢問,轉換為服務器(推送)有信息的時候就發(fā)送(當然客戶端還是等主動發(fā)送信息過來的喷市。。)寝并,沒有信息的時候就交給接線員(Nginx)腹备,不需要占用本身速度就慢的客服(Handler)了
——————–
至于怎么在不支持Websocket的客戶端上使用Websocket。馏谨。答案是:不能
但是可以通過上面說的long poll和ajax 輪詢來 模擬出類似的效果
喵喵喵 (`?ω?′)好啦,正文結束,這篇文章我看了感覺很好喇伯,不知道有沒有幫助到大家呢,話說回帖的人說話好萌好有趣艾猜,我感覺是個妹子呢捻悯,看人家妹子那么厲害,我還是個小渣渣今缚,我要加油了?