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

TCP沒那么難吧?這篇一定要看

網(wǎng)絡(luò) 通信技術(shù)
TCP相關(guān)的知識重要嗎?我覺得挺重要的,這些年來無論互聯(lián)網(wǎng)怎么變化,TCP協(xié)議本身都可以承載,仔細(xì)探究會發(fā)現(xiàn)它的設(shè)計的確夠巧妙,有許多值得借鑒的設(shè)計思想。
[[242081]]
2013年,慕尼黑

如今相當(dāng)多的程序員都是“互聯(lián)網(wǎng)程序員”,按說,應(yīng)該對互聯(lián)網(wǎng)的基礎(chǔ)協(xié)議相當(dāng)清楚。可惜至少就我的面試經(jīng)驗來看,許多人這方面缺課太多,簡單說說TCP/IP協(xié)議分層就已經(jīng)難倒了不少人。至于TCP/IP的“三次握手”,能說上來的人就相當(dāng)少了,如果再問問“為什么是三次握手”,基本就沒人能答上來了。一般的回答都是“這個太難”,或者“畢業(yè)太久,這個忘記了”。

如果臨時抱佛腳,把TCP的三次握手背下來應(yīng)付面試,確實能做到。但是要回答TCP為什么是三次握手,而不是兩次或者四次握手,光靠背就不行了——不信你去網(wǎng)絡(luò)上搜搜看,各種回答都有,眾說紛紜,不少提問者一頭霧水。

TCP相關(guān)的知識重要嗎?我覺得挺重要的,這些年來無論互聯(lián)網(wǎng)怎么變化,TCP協(xié)議本身都可以承載,仔細(xì)探究會發(fā)現(xiàn)它的設(shè)計的確夠巧妙,有許多值得借鑒的設(shè)計思想。

那么TCP真的很難嗎?為什么許多人背TCP的握手流程痛苦不堪,復(fù)述起來困難重重?我覺得,原因在于大家只把它當(dāng)成“既存事實”, 就像上中學(xué)時候背歷史政治那樣對待。但TCP可不是毫無邏輯的胡說,一旦 你搞清了設(shè)計思想和邏輯,就會發(fā)現(xiàn)理解起來一點也不困難。所以,今天我來做個簡單講解。

首先說說“三次握手”這個譯名,我確實覺得翻譯有誤(翻譯出版過一百多萬字技術(shù)資料,我自信還是有把握的)。我以前總記不住“三次握手”的過程,因為總覺得“握了三次手”,“握手”是雙方共同往中間湊的過程,這明顯和建連流程不符合。后來才發(fā)現(xiàn),“三次握手”的說法大概有問題。

“三次握手”的原文是three-way handshake,three-way更合適的翻譯恐怕是“三步”,所以整個名詞的意思是“需要三個步驟才能建立握手的機制”。這么解釋的好處是,“步”給人感覺更形象,就是“單方面邁一步”而已。實際上,RFC 793里說明了,握手過程也可以叫three-message handshake,通過三條消息來建立的握手。

那么,為什么要三步才能建立握手呢?我們可以暫時不理這個問題,想想如果我們自己來設(shè)計握手機制,應(yīng)當(dāng)怎么辦。

我們都知道,TCP是可靠的通訊協(xié)議,其“可靠性”就在于,任何一方要向另一方發(fā)數(shù)據(jù)(SYN),都必須收到確認(rèn)回應(yīng)(ACK)。同時TCP也是雙向的通訊協(xié)議,所以通訊的兩方都可以主動發(fā)送消息。

這里要澄清的一點,對許多“互聯(lián)網(wǎng)程序員”來說,TCP是掩蓋在HTTP之下的,大家熟悉的HTTP,它的經(jīng)典通訊模式是“一問一答”的,沒有請求就沒有應(yīng)答。不過這只是HTTP的特性,不是TCP的特性。在TCP協(xié)議里,客戶端和服務(wù)器都可以隨時主動向?qū)Ψ桨l(fā)送數(shù)據(jù)——也正是因為如此,改用HTTP/2之后服務(wù)器可以主動推送信息給客戶端,而不必改動TCP協(xié)議。

回到TCP,既然它是雙向、可靠的通訊,可以想見,建立連接就必須確認(rèn)雙方到對方的通訊都是可靠的,所以大概需要四步,發(fā)送四次消息。

 

如果軟件設(shè)計都這么簡單,那就太好了。可惜,世界上沒有那么簡單的事情。仔細(xì)觀察這幅圖,我們會發(fā)現(xiàn)幾個問題:

***,網(wǎng)絡(luò)通訊的成本是很高的,延遲往往無法預(yù)測,哪怕能少發(fā)送一次消息,也可以大大降低成本,提高效率。所以,建立連接的步驟上限應(yīng)當(dāng)是四步,下限是兩步,越少越好。

第二,兩輪SYN/ACK之間必須有關(guān)聯(lián),因為它們的功能相對獨立,都是確認(rèn)到對方的通訊可靠,卻同屬于一個“建立連接”的邏輯操作。如果兩輪完全獨立,那么如果兩輪中間間隔了特別特別長的時間,根本不是一個正常的建立連接的操作,程序卻無法識別,這顯然是不行的。所以,第二輪SYN/ACK必須要能夠和***輪SYN/ACK關(guān)聯(lián)起來。

再仔細(xì)看看,第二步和第三步都是從服務(wù)端給客戶端發(fā)消息,所以是不是可以合并起來?這樣起碼可以節(jié)省了一次網(wǎng)絡(luò)通訊。

 

像上面這樣直接在第二步把ACK和SYN合并起來,問題就解決了?

按照之前的分析,節(jié)省消息發(fā)送次數(shù)只是考慮之一,還需要考慮的是,第二輪SYN/ACK必須和***輪SYN/ACK掛鉤。

 

上面是TCP的數(shù)據(jù)報,包含了許多的控制位,用來標(biāo)識連接的狀態(tài)。其中最常見的是SYN、ACK、FIN:SYN表示synchronize,在建立連接時使用;ACK表示acknowledge,表示“確認(rèn)”收到了消息;FIN表示finish,在斷開連接時使用。

還要注意的兩個東西是SEQ NO和ACK NO。SEQ NO即Sequence Number,服務(wù)端和客戶端都會維護(hù)自己的SEQ NO,表示“已經(jīng)發(fā)送了多少數(shù)據(jù)”,單位是字節(jié);ACK NO即Acknowledge Number,用來回復(fù)確認(rèn),對應(yīng)SEQ NO的數(shù)據(jù)已經(jīng)收到。單獨說起來,這些概念都容易理解,只是注意不要混淆控制位的ACK和ACK NO——ACK是布爾值用來標(biāo)識數(shù)據(jù)報的類型,ACK NO是數(shù)值用來確認(rèn)已經(jīng)收到的數(shù)據(jù)。

基于上面的知識我們可以知道,在建立連接之初,數(shù)據(jù)報中的控制位SYN應(yīng)當(dāng)設(shè)定為1,表示“新建連接”;同時應(yīng)當(dāng)包含SEQ NO。此時的SEQ NO有個專門的名字叫ISN,也就是Initial Sequence Number(要注意,ISN只是用來稱呼這個特殊SEQ NO,并不存在專門的ISN字段)。

在服務(wù)端收到***個SYN消息的時候,它當(dāng)然需要發(fā)送ACK響應(yīng),但它如何確認(rèn)其中的SEQ NO“就是”新建連接的ISN,而不是來自姍姍來遲的某個古老連接呢?所以必須向客戶端確認(rèn)。恰恰因為第二步是ACK,SYN“合二為一”的獨特響應(yīng),所以收到這個消息時,客戶端就知道,既需要響應(yīng)其中的SYN,也需要核實其中的ACK(如果你仔細(xì)讀過RFC793就會知道,其中專門有一段提到了: A three way handshake is necessary because…… )

到了第三步,客戶端返回的消息里既包含對應(yīng)SYN的ACK,表示收到了服務(wù)端的消息,同時設(shè)定SEQ NO=ISN+1,確認(rèn)核實了ISN。服務(wù)端收到這條消息,確認(rèn)無誤是要建立新連接。至此,連接建立完畢。

 

大流程看起來就是這樣,也不難理解。不過仔細(xì)想想,還是有不少問題得考慮的。比如狀態(tài)問題,既然TCP是網(wǎng)絡(luò)通訊,會發(fā)生延遲,那么在“信息已經(jīng)發(fā)送,但還沒有收到確認(rèn)”的時候,應(yīng)當(dāng)是有個明確狀態(tài)的,否則會發(fā)生狀態(tài)的錯亂。實際上TCP也確實做到了這點,它背后有一臺完整的狀態(tài)機,確保每時每刻,每個動作發(fā)生之后,狀態(tài)都完全可控,一切盡在掌握,不會出現(xiàn)任何“孤點”和“斷頭路”。

 

上圖是TCP的狀態(tài)轉(zhuǎn)移圖的局部,覆蓋了建立鏈接的狀態(tài),感興趣的讀者可以按照自己實地走走看(說個題外話,“自己模擬在圖上走走”看起來土,其實高科技領(lǐng)域也挺常用。設(shè)計波音737的時候,開始大家都不知道發(fā)動機怎么擺比較好,設(shè)計師喬·薩特就在紙上畫出機身和發(fā)動機的模型,把發(fā)動機模型剪下來在飛機各處擺放,最終發(fā)現(xiàn)吊在翼下最合適)。

我在之前關(guān)于軟件設(shè)計的文章里幾次提到狀態(tài)圖、狀態(tài)轉(zhuǎn)移函數(shù),無論是用戶生命周期、訂單流轉(zhuǎn)過程,都可以用這個工具來解決。遺憾的是,我發(fā)現(xiàn)還有許多設(shè)計人員不懂得或者不習(xí)慣用使用它,實在很可惜。

回到TCP建立連接的過程,我們還要注意ISN。在建立連接時必須先確定ISN,通過它把客戶端和服務(wù)器的計數(shù)對齊。通常的教材上說,ISN是隨機生成的,這樣就保證了唯一性。 隨機的目的是保持唯一,但千萬不要以為“隨機就不會重復(fù)”,簡單的“取隨機數(shù)”是很容易碰撞的。所以傳統(tǒng)的“隨機”方案是維護(hù)一個時鐘和一個32位的計數(shù)器,時鐘每過4毫秒,計數(shù)器自增1。因為2^32毫秒就是差不多4個半小時(MSL,Max Segment Lifetime),這基本超出了任何數(shù)據(jù)包在網(wǎng)絡(luò)中的可能傳輸時間,所以可以認(rèn)為這種ISN是***的。

但這種方案也有風(fēng)險,既然這樣的ISN是連續(xù)的,那么中途的惡意程序可能能夠預(yù)測ISN的生成規(guī)律,從而偽造ISN…… 總之ISN的生成是個有趣的設(shè)計問題,這里不展開了,有興趣可以自己搜索資料閱讀。

我在開發(fā)中遇到不少程序員,一旦需要避免重復(fù),就想到“生成隨機數(shù)”,根本不管隨機數(shù)也可能碰撞。更有甚者,一旦遇到類似ISN的場合,就想當(dāng)然把初始值設(shè)定為0,真是讓人欲哭無淚(有沒有想過ISN為什么不能設(shè)定為0呢,歡迎留言討論)。

說完了建立連接的握手,我們再來看終止連接的揮手。通常大家都知道,TCP是“三次握手,四次揮手”(雖然我很不贊成“次”,但既然它已經(jīng)約定俗成,這里還是延用通用的說法吧)。那么,為什么要四次才能揮手呢?

知道這個答案的人比能講清楚“三次握手”的要多。通常的答案都是:TCP是雙向通訊協(xié)議,要結(jié)束連接,雙方都必須發(fā)送終止信號,告訴對方后續(xù)再沒有數(shù)據(jù)發(fā)過來了,并等待對方確認(rèn),所以一共需要2+2=4次。

 

如果你之前看過建立連接的過程,大概會有這樣的疑問:既然建立連接的時候可以節(jié)省一步,把服務(wù)端返回SYN和ACK合并到一起,那么結(jié)束連接的時候,是否也可以把服務(wù)端返回的SYN和FIN合并起來,節(jié)省一步呢?

想到了這個問題就值得恭喜,因為你不是只滿足于“知其然”,而希望“知其所以然”。不過我們也需要想到,既然TCP連接的建立和終止都是同一批人定義的,既然他們能想到在建立連接時節(jié)省一步,那么他們沒有理由在終止連接時不做節(jié)省。之所以沒有“節(jié)省”,一定是有理由存在的。

沒錯,確實是有理由的,而且這個理由很好理解,因為建立和終止連接的場景是不一樣的。在建立連接之前,客戶端和服務(wù)器端都不會向?qū)Ψ桨l(fā)送任何數(shù)據(jù),所以在服務(wù)端返回ACK的時候帶上SYN,客戶端當(dāng)然知道這是從服務(wù)端收到的***個數(shù)據(jù)包。

而在結(jié)束連接時,客戶端向服務(wù)端發(fā)送FIN,表示“我這邊不會繼續(xù)發(fā)送數(shù)據(jù)過來了”,服務(wù)端響應(yīng)ACK,這都沒有問題。但此時,服務(wù)端之前向客戶端發(fā)送數(shù)據(jù)的操作可能還沒有完成,服務(wù)端仍然在向客戶端傳輸數(shù)據(jù)。如果服務(wù)端把FIN和ACK合并起來,就會出現(xiàn)這樣的情況:客戶端的數(shù)據(jù)還沒有接受完,忽然收到服務(wù)端的消息“后續(xù)沒有數(shù)據(jù)了,終止連接”。顯然,這種情況不應(yīng)當(dāng)出現(xiàn),所以不能把ACK和FIN合并在一起,所以終止連接必須要四步。

最近和實習(xí)生聊天,說起開發(fā)中遇到的各種問題,以及對應(yīng)的模型,大家聽得入迷。事后有人問我:為什么我們工作中遇不到這么有意思的問題呢?我知道,這是個比較典型的問題。其實答案也很典型:因為你沒有去深究問題背后的原型。懂得了背后的原型,就具備了“從已知推導(dǎo)無知”的本領(lǐng),也具備了“從無知中發(fā)現(xiàn)已知”的眼光。

我和朋友聊開發(fā)有個共同的判斷:TCP的握手和揮手看起來簡單,但真讓如今的開發(fā)人員去設(shè)計握手和揮手流程,估計有超過一半的人設(shè)計不出穩(wěn)定、可靠、高效的握手和揮手流程。這樣說來,許多業(yè)務(wù)系統(tǒng)里業(yè)務(wù)層面的通訊極不可靠,協(xié)議設(shè)計錯漏百出,也是無奈的結(jié)果了。

補充一句。我曾在面試中遇到過這樣的人,非名校畢業(yè),已經(jīng)有五年工作經(jīng)驗,除了對流行的框架和熱點問題對答如流,對數(shù)據(jù)庫理論、網(wǎng)絡(luò)基礎(chǔ)知識、數(shù)據(jù)結(jié)構(gòu)和算法依然如數(shù)家珍。事實充分證明,不是所有人工作之后就把大學(xué)的知識丟個精光的,事實也證明,這樣的候選人確實能擔(dān)大任。

責(zé)任編輯:未麗燕 來源: 余晟以為
相關(guān)推薦

2018-11-27 15:55:21

TCP通訊協(xié)議

2018-09-04 15:10:40

2022-06-13 09:26:41

Promise前端代碼

2019-05-17 09:33:50

圖像識別三維重建文本識別

2012-12-21 09:31:52

Windows 8

2014-11-03 18:22:53

2021-07-01 07:34:09

LinuxIO模型

2022-10-17 06:22:36

Anaconda開源

2023-10-26 18:22:16

前端CSSFlex 布局

2016-12-12 15:28:01

蘋果移動開發(fā)者

2019-12-29 23:56:51

Python編程語言開發(fā)

2019-11-18 08:58:21

朋友圈自拍信息

2020-08-05 12:10:05

Web編程語言前端

2020-05-21 09:17:51

Vue 3Vue代碼

2015-08-24 14:36:53

2024-04-30 10:40:11

2019-03-05 09:21:21

IT黑客Redis

2018-03-16 10:07:30

霍金預(yù)言人工智能

2010-11-19 16:02:42

IT族

2019-06-25 10:02:44

程序員經(jīng)驗編程
點贊
收藏

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