關(guān)于TCP三次握手的理論知識(shí),往上一搜一大片,本文就跳過(guò)理論,直接上手。Let’s go。
準(zhǔn)備知識(shí)
抓一個(gè)TCP三次握手的包
開(kāi)啟三個(gè)窗口,窗口1執(zhí)行命令:
這個(gè)命令用來(lái)抓包,抓的是7899端口的包。-A和-X是為了顯示詳細(xì)的包內(nèi)容,方便分析。如果不習(xí)慣用tcpdump直接分析,也可以使用wireshark,更加直觀一些。
窗口2執(zhí)行命令:
該命令監(jiān)聽(tīng)7899端口,相當(dāng)于啟動(dòng)了一個(gè)監(jiān)聽(tīng)7899端口的server。當(dāng)然你要是有興趣的話,可以用代碼寫(xiě)一個(gè)server。
窗口3執(zhí)行命令:
這個(gè)命令是向127.0.0.1:7899建立連接,相當(dāng)于client執(zhí)行connect函數(shù)。
這個(gè)命令一執(zhí)行,就會(huì)連接到7899端口上 ,在第一個(gè)窗口上立即就會(huì)抓到連續(xù)的三個(gè)包,如下圖所示:
如上步驟,演示了TCP建立連接的過(guò)程,tcpdump抓到的三個(gè)包,正好就是三次握手。
很多資料講解三次握手時(shí),都會(huì)有一幅類(lèi)似于這樣的圖:
我們對(duì)應(yīng)抓到的三個(gè)包來(lái)看。
第一個(gè)包:
- 127.0.0.1.48448 > 127.0.0.1.7899 說(shuō)明是從client 發(fā)往server的, client的端口是48448
第二個(gè)包:
- 127.0.0.1.7899 > 127.0.0.1.48448 說(shuō)明是從server發(fā)往client的
第三個(gè)包:
- 127.0.0.1.48448 > 127.0.0.1.7899 從client發(fā)往server
這個(gè)步驟,和上圖大致是能一一對(duì)應(yīng)上的。
除了這些簡(jiǎn)而易見(jiàn)的信息,還有一些 可能一時(shí)半會(huì)兒看不懂的東西,比如:
要了解這些東西,需要先了解TCP協(xié)議棧。
tcpip,accept,11個(gè)狀態(tài),細(xì)枝末節(jié)的秘密
手寫(xiě)一個(gè)用戶態(tài)協(xié)議棧以及零拷貝的實(shí)現(xiàn)
netmap到dpdk,硬件到協(xié)議棧,4個(gè)維度構(gòu)建網(wǎng)絡(luò)體系
需要C/C++ Linux服務(wù)器架構(gòu)師學(xué)習(xí)資料加qun812855908獲?。?a href="http://www.delux-kingway.cn/soft/special/" target="_blank">資料包括C/C++,Linux,golang技術(shù),Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協(xié)程,DPDK,ffmpeg等),免費(fèi)分享
了解一下TCP協(xié)議棧
首先,我們應(yīng)該知道,一個(gè)完整的以太網(wǎng)幀,包含了ethdr + iphdr + tcpdhr + data + etend
其中,以太網(wǎng)頭占14字節(jié),IP頭占20字節(jié),TCP頭占20字節(jié),以太網(wǎng)尾占4字節(jié),應(yīng)用數(shù)據(jù)大小不定,但不會(huì)超過(guò)一個(gè)MTU。
因?yàn)槲覀冎谎芯咳挝帐郑躁P(guān)于以太網(wǎng)幀,了解這些就夠了。
我們?cè)賮?lái)看看具體的TCP協(xié)議棧:
TCP協(xié)議棧包含:
16位源端口號(hào),占2字節(jié)
16位目的端口號(hào),占2字節(jié)
32位序號(hào)(seq),占4字節(jié)
32位確認(rèn)序號(hào)(ack),占4字節(jié)
4位首部長(zhǎng)度,占0.5字節(jié)
6位保留位,占0.75字節(jié)
6位標(biāo)志位,占0.75字節(jié), 以上:4位首部長(zhǎng)度+6位保留長(zhǎng)度+6位標(biāo)志位,合計(jì)16位,計(jì)2字節(jié)
標(biāo)志位包括:
URG
- 緊急指針標(biāo)志
- 此標(biāo)志用于將輸入數(shù)據(jù)標(biāo)識(shí)為“緊急”。這樣的進(jìn)入段不必等待直到先前段被接收端消耗,而是直接發(fā)送并立即處理。
ACK - 用于確認(rèn)數(shù)據(jù)包的成功接收
PSH - 推送標(biāo)志
- 就是指數(shù)據(jù)包到達(dá)接收端以后,不對(duì)其進(jìn)行隊(duì)列處理,而是盡可能的將數(shù)據(jù)交給應(yīng)用程序處理
RST - 重置標(biāo)志
- 當(dāng)段到達(dá)不用于當(dāng)前連接時(shí),使用復(fù)位標(biāo)志,表示主機(jī)已重置連接
SYN - 發(fā)送/同步標(biāo)志
- 用來(lái)建立連接,一般和ACK搭配使用
FIN - 結(jié)束標(biāo)志
- 用于結(jié)束一個(gè)TCP會(huì)話, 一般用于四次揮手
16位窗口大?。╳indow size),占2字節(jié)
16位校驗(yàn)和(checksum),占2字節(jié)
16位緊急指針,占2字節(jié)
庖丁解牛,深度剖析TCP協(xié)議棧的三次握手
有了以上這些知識(shí),我們?cè)賮?lái)解析上面的協(xié)議棧。
第一個(gè)包
0x0000: 4510 003c dbf7 4000 4006 60b2 7f00 0001 E..<..@.@.`.....
0x0010: 7f00 0001 bd40 1edb b5dc f355 0000 0000 [email protected]....
0x0020: a002 ffd7 fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 7a57 2314 0000 0000 0103 0307 zW#.........
十六進(jìn)制報(bào)文中,前20個(gè)字節(jié)是IP協(xié)議頭,后20個(gè)字節(jié)雖然也屬于TCP協(xié)議 ,但是是可選項(xiàng)option,并非標(biāo)準(zhǔn)的TCP協(xié)議一定有的內(nèi)容,所以我們真正關(guān)心的內(nèi)容 , 是下面高亮的部分:
即:
接下來(lái),我們逐個(gè)字節(jié)解析:
16位源端口, 即 bd40, 轉(zhuǎn)換成10進(jìn)制為48448
16位目的端口,即1edb,轉(zhuǎn)換成10進(jìn)制為7899
- 從以上信息可知,該條消息是從48448發(fā)往7899端口,即客戶端發(fā)往服務(wù)端
32位序號(hào):b5dc f355, 即3051156309
32位確認(rèn)號(hào):0000 0000,即0
后面三個(gè)域由于不是 完整的字節(jié),放在一塊解析:
- a002翻譯成二進(jìn)制 ,為:1010 0000 0000 0010
- 其中,4位首部長(zhǎng)度,為1010,即10
- 6位保留字段,即0000 00,不做解釋
- 6位標(biāo)志位,即00 0010
標(biāo)志位要解釋一下 :
標(biāo)志位哪一位設(shè)置為1,就代表當(dāng)前屬于什么包
由上面對(duì)應(yīng)關(guān)系,可知當(dāng)前是一個(gè)SYN包。
16位窗口大?。篺fd7, 即65495
16位校驗(yàn)和,即:fe30
16位緊急指針,即0000
由以上內(nèi)容,我們提取一些關(guān)鍵信息:
第一次握手:
- 客戶端發(fā)往服務(wù)端
- 標(biāo)志位為SYN
- seq為3051156309
- ack為0
第二個(gè)包
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001 E..<..@.@.<.....
0x0010: 7f00 0001 1edb bd40 7916 41ca b5dc f356 [email protected]
0x0020: a012 ffcb fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 7a57 2314 7a57 2314 0103 0307 zW#.zW#.....
由上面的知識(shí),我們知道TCP報(bào)文主要是下面這段:
通過(guò)同樣的方法,可以解析出:
第二次握手:
- 服務(wù)端發(fā)往客戶端
- 標(biāo)志位為ACK+SYN
- seq為2031501770
- ack為3051156310, 正好是第一次握手的seq+1
第三個(gè)包
0x0000: 4510 0034 dbf8 4000 4006 60b9 7f00 0001 E..4..@.@.`.....
0x0010: 7f00 0001 bd40 1edb b5dc f356 7916 41cb [email protected].
0x0020: 8010 0200 fe28 0000 0101 080a 7a57 2314 .....(......zW#.
0x0030: 7a57 2314 zW#.
TCP協(xié)議部分:
可以解析出 :
第三次握手:
- 客戶端發(fā)往服務(wù)端
- 標(biāo)志位:ACK
- seq為3051156310,為第一次我收的 seq+1,也是第二次握手的ack
- ack為2031501771, 為 第二次握手的seq+1
歸納:
以上內(nèi)容,如果用比較直觀的方式總結(jié)一下 ,大約如下圖:
為什么需要三次握手
又回到老生常談的話題:為什么需要三次握手?少一次行不行?只握手一次成不成?
在聊這個(gè)話題之前,我們引入一下著名科幻小說(shuō)《三體》中葉文杰教主和三體文明建立聯(lián)系的過(guò)程。
首先,葉教主向三體文明發(fā)送了一條消息,緊接著,三體人回復(fù)了一條消息,內(nèi)容是“不要回答,不要回答,不要回答!”然后葉教主回復(fù)了這條消息 ,導(dǎo)致地球成功被三體人定位。
不得不說(shuō),大劉是懂TCP協(xié)議的。至少他懂三次握手的重要性。
第一次發(fā)消息,你說(shuō)三體人收到?jīng)]有?肯定是收到了的。但這個(gè)連接可靠不?明顯不可靠。對(duì)于三體人來(lái)說(shuō),他怎么知道這個(gè)消息是誰(shuí)發(fā)的?發(fā)消息的文明是否還活著?對(duì)于地球來(lái)說(shuō),更是如此,他怎么知道 這條消息對(duì)方肯定收到了?又沒(méi)有人收?
第二次發(fā)消息,三體人差不多要把ACK標(biāo)志寫(xiě)在臉上了,就是明明白白告訴你,我這是一個(gè)ACK消息,你只要不應(yīng)答這個(gè)ACK,我們這個(gè)連接就建立不成,三體小說(shuō)就全劇終。這就相當(dāng)于三體人告訴葉教主:我活著,并且能收到你的消息,但是我還不知道你是誰(shuí),你能不能收到我這條消息。
所以第三條消息,狡猾的大劉當(dāng)然不會(huì)讓三體就此game over,就是老葉告訴三體人,我也能收到你的消息,從此以后,咱們是“同志”了。
類(lèi)比三次握手,和這個(gè)步驟非常相似,缺少其中任意一環(huán),這個(gè)連接都是不可靠的,因?yàn)槟悴恢缹?duì)方能不能收到我的消息。所以三次握手,并不是表示連接“可達(dá)”的,而是表示連接“可靠”的。這之間是有區(qū)別的,可達(dá)很簡(jiǎn)單,UDP也能可達(dá),一次握手也是可達(dá)的,但是并不可靠。因?yàn)闊o(wú)法知道這條消息對(duì)方能不能正確接收到。只有這樣反復(fù)確認(rèn)后,才能表示這個(gè)連接是可靠的連接。
有杠精肯定表示不服,說(shuō)理雖然是這么個(gè)理,但是會(huì)不會(huì)有巧合啊。比如某個(gè)服務(wù)既是客戶端又是服務(wù)端,我在給你發(fā)第一次握手的時(shí)候,你也恰好在給我發(fā)第一次握手,讓我誤以為你給我的消息是第二次握手的回包,從而建立了一個(gè)不可靠的連接?
而杠精之所以是杠精,就是因?yàn)槟居心X子。你考慮的問(wèn)題,咱們祖師爺肯定都考慮到了。
我們?cè)谇懊娣治鋈挝帐值倪^(guò)程的時(shí)候,為什么要強(qiáng)調(diào)ack = 上一次的seq+1?就是代表我不僅收到了你的,我還在你的seq上加1,代表我收到的確實(shí)是你的消息,這就相當(dāng)于給這條消息打上了獨(dú)一無(wú)二的標(biāo)志,別人想魚(yú)目混珠都不可能。
最后,咱們說(shuō)說(shuō),三體人和葉文杰建立的是TCP連接嗎?咳咳,明顯不是。本文只是舉例類(lèi)比。要知道,葉文杰第一個(gè)包可是broadcast,誰(shuí)都能收到的。
-
TCP
+關(guān)注
關(guān)注
8文章
1378瀏覽量
79335 -
端口
+關(guān)注
關(guān)注
4文章
990瀏覽量
32233 -
窗口
+關(guān)注
關(guān)注
0文章
66瀏覽量
10899 -
代碼
+關(guān)注
關(guān)注
30文章
4831瀏覽量
69112
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
講一講的TCP三次握手和四次揮手
![講一講的<b class='flag-5'>TCP</b><b class='flag-5'>三次</b><b class='flag-5'>握手</b>和四<b class='flag-5'>次</b>揮手](https://file.elecfans.com/web2/M00/8D/A1/poYBAGPcdoyAD6EqAABv3DPI5vA713.png)
評(píng)論