自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么有HTTP協(xié)議,還要有websocket協(xié)議

網(wǎng)絡(luò) 通信技術(shù)
這是由于HTTP協(xié)議設(shè)計(jì)之初,考慮的是看看網(wǎng)頁(yè)文本的場(chǎng)景,能做到客戶端發(fā)起請(qǐng)求再由服務(wù)器響應(yīng),就夠了,根本就沒(méi)考慮網(wǎng)頁(yè)游戲這種,客戶端和服務(wù)器之間都要互相主動(dòng)發(fā)大量數(shù)據(jù)的場(chǎng)景。

?平時(shí)我們打開(kāi)網(wǎng)頁(yè),比如購(gòu)物網(wǎng)站某寶。都是點(diǎn)一下列表商品,跳轉(zhuǎn)一下網(wǎng)頁(yè)就到了商品詳情。

從HTTP協(xié)議的角度來(lái)看,就是點(diǎn)一下網(wǎng)頁(yè)上的某個(gè)按鈕,前端發(fā)一次HTTP請(qǐng)求,網(wǎng)站返回一次HTTP響應(yīng)。

這種由客戶端主動(dòng)請(qǐng)求,服務(wù)器響應(yīng)的方式也滿足大部分網(wǎng)頁(yè)的功能場(chǎng)景。

但有沒(méi)有發(fā)現(xiàn),這種情況下,服務(wù)器從來(lái)就不會(huì)主動(dòng)給客戶端發(fā)一次消息。

就像你喜歡的女生從來(lái)不會(huì)主動(dòng)找你一樣。

但如果現(xiàn)在,你在刷網(wǎng)頁(yè)的時(shí)候右下角突然彈出一個(gè)小廣告,提示你【一個(gè)人在家偷偷才能玩哦】。

求知,好學(xué),勤奮,這些刻在你DNA里的東西都動(dòng)起來(lái)了。

你點(diǎn)開(kāi)后發(fā)現(xiàn)。

長(zhǎng)相平平無(wú)奇的古某提示你"道士9條狗,全服橫著走"。

影帝某輝老師跟你說(shuō)"系兄弟就來(lái)砍我"。

來(lái)都來(lái)了,你就選了個(gè)角色進(jìn)到了游戲界面里。

這時(shí)候,上來(lái)就是一個(gè)小怪,從遠(yuǎn)處走來(lái),然后瘋狂拿木棒子抽你。

你全程沒(méi)點(diǎn)任何一次鼠標(biāo)。服務(wù)器就自動(dòng)將怪物的移動(dòng)數(shù)據(jù)和數(shù)據(jù)源源不斷發(fā)給你了。

這….太暖心了。

感動(dòng)之余,問(wèn)題就來(lái)了,

像這種看起來(lái)服務(wù)器主動(dòng)發(fā)消息給客戶端的場(chǎng)景,是怎么做到的?

在真正回答這個(gè)問(wèn)題之前,我們先來(lái)聊下一些相關(guān)的知識(shí)背景。

使用HTTP不斷輪詢

其實(shí)問(wèn)題的痛點(diǎn)在于,怎么樣才能在用戶不做任何操作的情況下,網(wǎng)頁(yè)能收到消息并發(fā)生變更。

最常見(jiàn)的解決方案是,網(wǎng)頁(yè)的前端代碼里不斷定時(shí)發(fā)HTTP請(qǐng)求到服務(wù)器,服務(wù)器收到請(qǐng)求后給客戶端響應(yīng)消息。

這其實(shí)時(shí)一種偽服務(wù)器推的形式。

它其實(shí)并不是服務(wù)器主動(dòng)發(fā)消息到客戶端,而是客戶端自己不斷偷偷請(qǐng)求服務(wù)器,只是用戶無(wú)感知而已。

用這種方式的場(chǎng)景也有很多,最常見(jiàn)的就是掃碼登錄。

比如某信公眾號(hào)平臺(tái),登錄頁(yè)面二維碼出現(xiàn)之后,前端網(wǎng)頁(yè)根本不知道用戶掃沒(méi)掃,于是不斷去向后端服務(wù)器詢問(wèn),看有沒(méi)有人掃過(guò)這個(gè)碼。而且是以大概1到2秒的間隔去不斷發(fā)出請(qǐng)求,這樣可以保證用戶在掃碼后能在1到2s內(nèi)得到及時(shí)的反饋,不至于等太久。

圖片

使用HTTP定時(shí)輪詢

但這樣,會(huì)有兩個(gè)比較明顯的問(wèn)題

  • 當(dāng)你打開(kāi)F12頁(yè)面時(shí),你會(huì)發(fā)現(xiàn)滿屏的HTTP請(qǐng)求。雖然很小,但這其實(shí)也消耗帶寬,同時(shí)也會(huì)增加下游服務(wù)器的負(fù)擔(dān)。
  • 最壞情況下,用戶在掃碼后,需要等個(gè)1~2s,正好才觸發(fā)下一次http請(qǐng)求,然后才跳轉(zhuǎn)頁(yè)面,用戶會(huì)感到明顯的卡頓。

使用起來(lái)的體驗(yàn)就是,二維碼出現(xiàn)后,手機(jī)掃一掃,然后在手機(jī)上點(diǎn)個(gè)確認(rèn),這時(shí)候卡頓等個(gè)1~2s,頁(yè)面才跳轉(zhuǎn)。

圖片

不斷輪詢查看是否有掃碼

那么問(wèn)題又來(lái)了,有沒(méi)有更好的解決方案?

有,而且實(shí)現(xiàn)起來(lái)成本還非常低。

長(zhǎng)輪詢

我們知道,HTTP請(qǐng)求發(fā)出后,一般會(huì)給服務(wù)器留一定的時(shí)間做響應(yīng),比如3s,規(guī)定時(shí)間內(nèi)沒(méi)返回,就認(rèn)為是超時(shí)。

如果我們的HTTP請(qǐng)求將超時(shí)設(shè)置的很大,比如30s,在這30s內(nèi)只要服務(wù)器收到了掃碼請(qǐng)求,就立馬返回給客戶端網(wǎng)頁(yè)。如果超時(shí),那就立馬發(fā)起下一次請(qǐng)求。

這樣就減少了HTTP請(qǐng)求的個(gè)數(shù),并且由于大部分情況下,用戶都會(huì)在某個(gè)30s的區(qū)間內(nèi)做掃碼操作,所以響應(yīng)也是及時(shí)的。

圖片

長(zhǎng)輪詢

比如,某度云網(wǎng)盤就是這么干的。所以你會(huì)發(fā)現(xiàn)一掃碼,手機(jī)上點(diǎn)個(gè)確認(rèn),電腦端網(wǎng)頁(yè)就秒跳轉(zhuǎn),體驗(yàn)很好。

圖片

長(zhǎng)輪詢的方式來(lái)替代

真一舉兩得。

像這種發(fā)起一個(gè)請(qǐng)求,在較長(zhǎng)時(shí)間內(nèi)等待服務(wù)器響應(yīng)的機(jī)制,就是所謂的長(zhǎng)訓(xùn)輪機(jī)制。我們常用的消息隊(duì)列RocketMQ中,消費(fèi)者去取數(shù)據(jù)時(shí),也用到了這種方式。

圖片

RocketMQ的消費(fèi)者通過(guò)長(zhǎng)輪詢獲取數(shù)據(jù)

像這種,在用戶不感知的情況下,服務(wù)器將數(shù)據(jù)推送給瀏覽器的技術(shù),就是所謂的服務(wù)器推送技術(shù),它還有個(gè)毫不沾邊的英文名,comet技術(shù),大家聽(tīng)過(guò)就好。

上面提到的兩種解決方案,本質(zhì)上,其實(shí)還是客戶端主動(dòng)去取數(shù)據(jù)。

對(duì)于像掃碼登錄這樣的簡(jiǎn)單場(chǎng)景還能用用。

但如果是網(wǎng)頁(yè)游戲呢,游戲一般會(huì)有大量的數(shù)據(jù)需要從服務(wù)器主動(dòng)推送到客戶端。

這就得說(shuō)下websocket了。

websocket是什么

我們知道TCP連接的兩端,同一時(shí)間里,雙方都可以主動(dòng)向?qū)Ψ桨l(fā)送數(shù)據(jù)。這就是所謂的全雙工。

而現(xiàn)在使用最廣泛的HTTP1.1,也是基于TCP協(xié)議的,同一時(shí)間里,客戶端和服務(wù)器只能有一方主動(dòng)發(fā)數(shù)據(jù),這就是所謂的半雙工。

也就是說(shuō),好好的全雙工TCP,被HTTP用成了半雙工。

為什么?

這是由于HTTP協(xié)議設(shè)計(jì)之初,考慮的是看看網(wǎng)頁(yè)文本的場(chǎng)景,能做到客戶端發(fā)起請(qǐng)求再由服務(wù)器響應(yīng),就夠了,根本就沒(méi)考慮網(wǎng)頁(yè)游戲這種,客戶端和服務(wù)器之間都要互相主動(dòng)發(fā)大量數(shù)據(jù)的場(chǎng)景。

所以為了更好的支持這樣的場(chǎng)景,我們需要另外一個(gè)基于TCP的新協(xié)議。

于是新的應(yīng)用層協(xié)議websocket就被設(shè)計(jì)出來(lái)了。

大家別被這個(gè)名字給帶偏了。雖然名字帶了個(gè)socket,但其實(shí)socket和websocket之間,就跟雷峰和雷峰塔一樣,二者接近毫無(wú)關(guān)系。

圖片

websocket在四層網(wǎng)絡(luò)協(xié)議中的位置

怎么建立websocket連接

我們平時(shí)刷網(wǎng)頁(yè),一般都是在瀏覽器上刷的,一會(huì)刷刷圖文,這時(shí)候用的是HTTP協(xié)議,一會(huì)打開(kāi)網(wǎng)頁(yè)游戲,這時(shí)候就得切換成我們新介紹的websocket協(xié)議。

為了兼容這些使用場(chǎng)景。瀏覽器在TCP三次握手建立連接之后,都統(tǒng)一使用HTTP協(xié)議先進(jìn)行一次通信。

  • 如果此時(shí)是普通的HTTP請(qǐng)求,那后續(xù)雙方就還是老樣子繼續(xù)用普通HTTP協(xié)議進(jìn)行交互,這點(diǎn)沒(méi)啥疑問(wèn)。
  • 如果這時(shí)候是想建立websocket連接,就會(huì)在HTTP請(qǐng)求里帶上一些特殊的header頭。
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n

這些header頭的意思是,瀏覽器想升級(jí)協(xié)議(Connection: Upgrade),并且想升級(jí)成websocket協(xié)議(Upgrade: websocket)。

同時(shí)帶上一段隨機(jī)生成的base64碼(Sec-WebSocket-Key),發(fā)給服務(wù)器。

如果服務(wù)器正好支持升級(jí)成websocket協(xié)議。就會(huì)走websocket握手流程,同時(shí)根據(jù)客戶端生成的base64碼,用某個(gè)公開(kāi)的算法變成另一段字符串,放在HTTP響應(yīng)的 Sec-WebSocket-Accept? 頭里,同時(shí)帶上101狀態(tài)碼,發(fā)回給瀏覽器。

HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n

http狀態(tài)碼=200(正常響應(yīng))的情況,大家見(jiàn)得多了。101確實(shí)不常見(jiàn),它其實(shí)是指協(xié)議切換。

圖片

base64轉(zhuǎn)為新的字符串

之后,瀏覽器也用同樣的公開(kāi)算法將base64碼轉(zhuǎn)成另一段字符串,如果這段字符串跟服務(wù)器傳回來(lái)的字符串一致,那驗(yàn)證通過(guò)。

圖片

對(duì)比客戶端和服務(wù)端生成的字符串

就這樣經(jīng)歷了一來(lái)一回兩次HTTP握手,websocket就建立完成了,后續(xù)雙方就可以使用webscoket的數(shù)據(jù)格式進(jìn)行通信了。

圖片

建立websocket連接.drawio

websocket抓包

我們可以用wireshark抓個(gè)包,實(shí)際看下數(shù)據(jù)包的情況。

圖片

客戶端請(qǐng)求升級(jí)為websocket

上面這張圖,注意畫了紅框的第2445?行報(bào)文,是websocket的第一次握手,意思是發(fā)起了一次帶有特殊Header的HTTP請(qǐng)求。

圖片

服務(wù)器同意升級(jí)為websocket協(xié)議

上面這個(gè)圖里畫了紅框的4714?行報(bào)文,就是服務(wù)器在得到第一次握手后,響應(yīng)的第二次握手,可以看到這也是個(gè)HTTP類型的報(bào)文,返回的狀態(tài)碼是101。同時(shí)可以看到返回的報(bào)文header中也帶有各種websocket?相關(guān)的信息,比如Sec-WebSocket-Accept。

圖片

兩次HTTP請(qǐng)求之后正式使用websocket通信

上面這張圖就是全貌了,從截圖上的注釋可以看出,websocket和HTTP一樣都是基于TCP的協(xié)議。經(jīng)歷了三次TCP握手之后,利用HTTP協(xié)議升級(jí)為websocket協(xié)議。

你在網(wǎng)上可能會(huì)看到一種說(shuō)法:"websocket是基于HTTP的新協(xié)議",其實(shí)這并不對(duì),因?yàn)閣ebsocket只有在建立連接時(shí)才用到了HTTP,升級(jí)完成之后就跟HTTP沒(méi)有任何關(guān)系了。

這就好像你喜歡的女生通過(guò)你要到了你大學(xué)室友的微信,然后他們自己就聊起來(lái)了。你能說(shuō)這個(gè)女生是通過(guò)你去跟你室友溝通的嗎?不能。你跟HTTP一樣,都只是個(gè)工具人。

這就有點(diǎn)"借殼生蛋"的那意思。

圖片

HTTP和websocket的關(guān)系

websocket的消息格式

上面提到在完成協(xié)議升級(jí)之后,兩端就會(huì)用webscoket的數(shù)據(jù)格式進(jìn)行通信。

數(shù)據(jù)包在websocket中被叫做幀。

我們來(lái)看下它的數(shù)據(jù)格式長(zhǎng)什么樣子。

圖片

websocket報(bào)文格式

這里面字段很多,但我們只需要關(guān)注下面這幾個(gè)。

opcode字段:這個(gè)是用來(lái)標(biāo)志這是個(gè)什么類型的數(shù)據(jù)幀。比如。

等于1時(shí)是指text類型(string)的數(shù)據(jù)包

等于2是二進(jìn)制數(shù)據(jù)類型([]byte)的數(shù)據(jù)包

等于8是關(guān)閉連接的信號(hào)

payload字段:存放的是我們真正想要傳輸?shù)臄?shù)據(jù)的長(zhǎng)度,單位是字節(jié)。比如你要發(fā)送的數(shù)據(jù)是字符串"111"?,那它的長(zhǎng)度就是3。

圖片

另外,可以看到,我們存放payload長(zhǎng)度的字段有好幾個(gè),我們既可以用最前面的7bit?, 也可以用后面的7+16bit或7+64bit。

那么問(wèn)題就來(lái)了。

我們知道,在數(shù)據(jù)層面,大家都是01二進(jìn)制流。我怎么知道什么情況下應(yīng)該讀7bit,什么情況下應(yīng)該讀7+16bit呢?

websocket會(huì)用最開(kāi)始的7bit做標(biāo)志位。不管接下來(lái)的數(shù)據(jù)有多大,都先讀最先的7個(gè)bit,根據(jù)它的取值決定還要不要再讀個(gè)16bit或64bit。

  • 如果最開(kāi)始的7bit的值是 0~125,那么它就表示了 payload 全部長(zhǎng)度,只讀最開(kāi)始的7個(gè)bit就完事了。

圖片

payload長(zhǎng)度在0到125之間

  • 如果是126(0x7E)。那它表示payload的長(zhǎng)度范圍在 126~65535 之間,接下來(lái)還需要再讀16bit。這16bit會(huì)包含payload的真實(shí)長(zhǎng)度。

圖片

payload長(zhǎng)度在126到65535之間

  • 如果是127(0x7F)。那它表示payload的長(zhǎng)度范圍>=65536,接下來(lái)還需要再讀64bit。這64bit會(huì)包含payload的長(zhǎng)度。這能放2的64次方byte的數(shù)據(jù),換算一下好多個(gè)TB,肯定夠用了。

圖片

payload長(zhǎng)度大于等于65536的情況

payload data字段:這里存放的就是真正要傳輸?shù)臄?shù)據(jù),在知道了上面的payload長(zhǎng)度后,就可以根據(jù)這個(gè)值去截取對(duì)應(yīng)的數(shù)據(jù)。

大家有沒(méi)有發(fā)現(xiàn)一個(gè)小細(xì)節(jié),websocket的數(shù)據(jù)格式也是  數(shù)據(jù)頭(內(nèi)含payload長(zhǎng)度) + payload data 的形式。

之前寫的《既然有HTTP協(xié)議,為什么還要有RPC》提到過(guò),TCP協(xié)議本身就是全雙工,但直接使用純裸TCP去傳輸數(shù)據(jù),會(huì)有粘包的"問(wèn)題"。為了解決這個(gè)問(wèn)題,上層協(xié)議一般會(huì)用消息頭+消息體的格式去重新包裝要發(fā)的數(shù)據(jù)。

而消息頭里一般含有消息體的長(zhǎng)度,通過(guò)這個(gè)長(zhǎng)度可以去截取真正的消息體。

HTTP協(xié)議和大部分RPC協(xié)議,以及我們今天介紹的websocket協(xié)議,都是這樣設(shè)計(jì)的。

圖片

消息邊界長(zhǎng)度標(biāo)志

websocket的使用場(chǎng)景

websocket完美繼承了TCP協(xié)議的全雙工能力,并且還貼心的提供了解決粘包的方案。它適用于需要服務(wù)器和客戶端(瀏覽器)頻繁交互的大部分場(chǎng)景。比如網(wǎng)頁(yè)/小程序游戲,網(wǎng)頁(yè)聊天室,以及一些類似飛書這樣的網(wǎng)頁(yè)協(xié)同辦公軟件。

回到文章開(kāi)頭的問(wèn)題,在使用websocket協(xié)議的網(wǎng)頁(yè)游戲里,怪物移動(dòng)以及玩家的行為是服務(wù)器邏輯產(chǎn)生的,對(duì)玩家產(chǎn)生的傷害等數(shù)據(jù),都需要由服務(wù)器主動(dòng)發(fā)送給客戶端,客戶端獲得數(shù)據(jù)后展示對(duì)應(yīng)的效果。

圖片

websocket的使用場(chǎng)景

總結(jié)

  • TCP協(xié)議本身是全雙工的,但我們最常用的HTTP1.1,雖然是基于TCP的協(xié)議,但它是半雙工的,對(duì)于大部分需要服務(wù)器主動(dòng)推送數(shù)據(jù)到客戶端的場(chǎng)景,都不太友好,因此我們需要使用支持全雙工的websocket協(xié)議。
  • 在HTTP1.1里。只要客戶端不問(wèn),服務(wù)端就不答?;谶@樣的特點(diǎn),對(duì)于登錄頁(yè)面這樣的簡(jiǎn)單場(chǎng)景,可以使用定時(shí)輪詢或者長(zhǎng)輪詢的方式實(shí)現(xiàn)服務(wù)器推送(comet)的效果。
  • 對(duì)于客戶端和服務(wù)端之間需要頻繁交互的復(fù)雜場(chǎng)景,比如網(wǎng)頁(yè)游戲,都可以考慮使用websocket協(xié)議。
  • websocket和socket幾乎沒(méi)有任何關(guān)系,只是叫法相似。
  • 正因?yàn)楦鱾€(gè)瀏覽器都支持HTTP協(xié)議,所以websocket會(huì)先利用HTTP協(xié)議加上一些特殊的header頭進(jìn)行握手升級(jí)操作,升級(jí)成功后就跟HTTP沒(méi)有任何關(guān)系了,之后就用websocket的數(shù)據(jù)格式進(jìn)行收發(fā)數(shù)據(jù)。?
責(zé)任編輯:武曉燕 來(lái)源: 小白debug
相關(guān)推薦

2023-09-07 08:07:56

goHTTP網(wǎng)絡(luò)

2022-07-19 08:01:32

HTTP協(xié)議RPC

2023-10-24 15:15:26

HTTPWebSocket

2021-10-12 18:48:07

HTTP 協(xié)議Websocket網(wǎng)絡(luò)通信

2019-07-15 14:12:01

UDPIP協(xié)議

2022-06-07 08:39:35

RPCHTTP

2023-01-12 09:01:01

MongoDBMySQL

2024-07-11 10:41:07

HTTPSHTTP文本傳輸協(xié)議

2020-11-25 09:36:17

HTTPRPC遠(yuǎn)程

2022-07-12 08:56:18

公平鎖非公平鎖Java

2022-03-18 10:43:12

WebSocketHTML5TCP 連接

2019-07-04 10:49:13

HTTPWebSocket協(xié)議

2021-05-10 08:32:32

Websocket協(xié)議http

2020-09-12 13:55:03

HTTP3.0UDP協(xié)議

2021-10-18 08:35:50

HTTPSHTTP協(xié)議

2020-03-10 08:27:24

TCP粘包網(wǎng)絡(luò)協(xié)議

2020-11-30 15:40:40

技術(shù)資訊

2010-06-17 15:53:41

WAP協(xié)議

2022-12-22 21:01:11

2017-05-26 10:35:13

前端HTTP
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)