作為一個程序猿,對造輪子這事情可以說是情有獨鐘,幾乎程序猿內(nèi)心都存在一個夢想是去將開源的技術(shù)都實現(xiàn)一遍,所有從本篇開始,我會開一個造輪子系列。 前言首先,看看這個,想必大家對下面這種簡歷看得比較多了吧?
上面每一條都涉及好多輪子,每一個都是精通,如果真能做到。那這個人可以說是碼農(nóng)中的戰(zhàn)斗機。 那我們現(xiàn)在目標(biāo)就是去做這個戰(zhàn)斗機。而這個方法,就是自己去造輪子,造的目的不是為了在項目中使用自己造的輪子,而是為了去了解輪子的構(gòu)造,然后自己動手去體會造輪子的過程。 后端的輪子們說起后端的輪子們,大家都可以說出一大串來,我們大致來數(shù)一數(shù)啊。
本文主要講http協(xié)議。 正文分割線 我們都知道http是基于tcp之上的,那我們現(xiàn)在就自己基于tcp來實現(xiàn)一個最小的http服務(wù),功能非常簡單:
先來看請求格式: ![]() http的報文大概分為3部分:
此處請求行是格式是固定的, 先寫代碼來看看的: ![]() ![]() 可以看到我們讀取的到數(shù)據(jù)是如上,我們可以看到格式上是符合的。 Ps:上面這個代碼有個小問題,因為tcp連接是字節(jié)流的,我們通過readAll方法從連接中讀取數(shù)據(jù)的是,只要瀏覽器上不主動斷開,會一直阻塞在readaALL上。。。 上面我們將收到的數(shù)據(jù)稍微整理下
上面首部中Content-length: 0可以說是非常關(guān)鍵,他告訴了我們應(yīng)該要在兩個\r\n后繼續(xù)讀取多少字節(jié)。 下面我們開始來寫解析代碼,先是解析文件頭 ![]() 然后我們再解析首部 ![]() 解析完后,我們在寫返回值,返回報文的格式放下: ![]() 下面是返回值的代碼: ![]() 完整的例子可以看GitHub上代碼,歡迎star https://github.com/zhuanxuhit/go-in-practice/tree/master/wheel/http/v1 我們有了第一版http輪子后,我們能和前面介紹的輪子系列:rpc聯(lián)系起來,在rpc系列中,我們講了設(shè)計通信協(xié)議來傳遞消息,此處http是通過頭部的url+method的方法來表示我要調(diào)用服務(wù)端哪個方法,然后分割符是使用 \r\n,連續(xù)兩個\r\n表示后續(xù)是消息體,為了高速我們消息體的大小和格式,在header中必須指明content-type和content-length,這些都是在我們在實現(xiàn)http協(xié)議的時候遵循的。 那現(xiàn)在寫完最初版代碼,我們回過頭總結(jié)下我們之前做的rpc輪子,數(shù)據(jù)編碼采用了protobuf,然后基于tcp自己定義了一套消息協(xié)議,其實做的事情跟http/1.1是一樣的,我們完全可以在http通信的時候,將content-type設(shè)置為protobuf,然后通信雙方雙方能夠編解碼即可。 在實現(xiàn)過程中,我們發(fā)現(xiàn)如果用http1.1作為通信協(xié)議,有什么問題呢?
那上面這兩點都是要解決的問題,在http2.0中都有相應(yīng)的方案
那怎么能做到一個連接同時發(fā)起多個請求呢?通信雙方就必須對每個請求進行編碼,這樣不同的響應(yīng)就能和請求對應(yīng)上了。 具體可以看兩張圖: ![]() HTTP 2.0 其實是將三個請求變成三個流,將數(shù)據(jù)分成幀,亂序發(fā)送到一個tcp連接中 ![]() 通過stream對不同請求進行區(qū)分,然后在將一個消息拆分為多個幀進行發(fā)送。 那http2.0后,還能不能更快了呢?于是就有了QUIC協(xié)議,這個協(xié)議肯定是為了解決http2.0的某些問題的。
![]() 重傳有個測不準(zhǔn)問題,左邊是1.1,我們發(fā)現(xiàn)重發(fā)100編號的時候,如果后續(xù)收到應(yīng)答101,我們不知道這個是針對第一次100的應(yīng)答還是第二次重傳100的應(yīng)答,http2.0則定義了每次發(fā)送數(shù)據(jù),編號都需要增加,然后通過offset來標(biāo)明數(shù)據(jù)的前后續(xù)關(guān)系。
總結(jié)首先本文基于tcp自己實現(xiàn)了http1.1的協(xié)議,實現(xiàn)中發(fā)現(xiàn)這個通信協(xié)議和我們之前輪子系列文章rpc都是消息協(xié)議,只是對消息體的編碼格式不同而已。 接著我們在自己寫的過程中發(fā)現(xiàn)了http1.1的種種問題,針對這些問題有了http2.0,繼而又有了QUIC。 預(yù)告:今天講完http2.0后,我會接著講輪子系列:gRpc,這個通信協(xié)議使用就是http2.0,歡迎大家關(guān)注。 Ps:文章最后關(guān)于http2.0和quic的內(nèi)容主要來自極客時間的趣談網(wǎng)絡(luò)協(xié)議,寫的真的非常好,大家可以去訂閱的,當(dāng)然通過我的邀請碼可以有返現(xiàn)的,歡迎加wx: hithangtian 源碼地址:https://github.com/zhuanxuhit/go-in-practice/tree/master/wheel/http/v1 |
|