1.TCP協(xié)議
為什么需要 TCP 協(xié)議 ?TCP 工作在哪一層?
IP網(wǎng)絡(luò)層是不可靠的,TCP工作在傳輸層,保證數(shù)據(jù)傳輸?shù)目煽啃浴?TCP全稱為 “傳輸控制協(xié)議(Transmission Control Protocol”)。
TCP 是面向連接的、可靠的、基于字節(jié)流:
- 面向連接:一定是「一對(duì)一」才能連接,不能像 UDP 協(xié)議可以一個(gè)主機(jī)同時(shí)向多個(gè)主機(jī)發(fā)送消息,也就是一對(duì)多是無法做到的;
- 可靠的:無論的網(wǎng)絡(luò)鏈路中出現(xiàn)了怎樣的鏈路變化,TCP有很多策略 都可以保證一個(gè)報(bào)文一定能夠到達(dá)接收端;
- 字節(jié)流:用戶消息通過 TCP 協(xié)議傳輸時(shí),消息可能會(huì)被操作系統(tǒng)「分組」成多個(gè)的 TCP 報(bào)文,如果接收方的程序如果不知道「消息的邊界」,是無法讀出一個(gè)有效的用戶消息的。
2.TCP協(xié)議格式詳解
-
源端口號(hào)和目的端口號(hào):表示數(shù)據(jù)是從哪個(gè)進(jìn)程來, 到哪個(gè)進(jìn)程去。通過端口號(hào)將報(bào)文交付給上一層
-
4位TCP報(bào)頭長(zhǎng)度: 表示該TCP頭部有多少個(gè)32位bit(有多少個(gè)4字節(jié))。4個(gè)比特位[0000 -1111]最大是15再乘以4個(gè)字節(jié)(單位),一共能表示60個(gè)字節(jié)。報(bào)頭長(zhǎng)度 = 固定長(zhǎng)度(20字節(jié)) + 選項(xiàng)。通過4位TCP報(bào)頭長(zhǎng)度就可以將一個(gè)完整報(bào)文的報(bào)頭和有效載荷分離。
-
窗口大?。和ㄟ^read這樣的接口,是將用戶級(jí)緩沖區(qū)的數(shù)據(jù)拷貝都系統(tǒng)級(jí)緩沖區(qū)中,主機(jī)再將數(shù)據(jù)通過網(wǎng)絡(luò)發(fā)送到目標(biāo)主機(jī),其實(shí)網(wǎng)絡(luò)的發(fā)送本質(zhì)也是拷貝。那么如果數(shù)據(jù)一直發(fā),對(duì)方?jīng)]有來得及接收,大量的數(shù)據(jù)"打滿"了接收緩沖區(qū)導(dǎo)致數(shù)據(jù)丟包的問題,這是一種不可靠的表現(xiàn)。TCP保證可靠性,通過16位窗口大小來填寫自己接收緩沖區(qū)的剩余空間,告知對(duì)方進(jìn)行流量控制。
窗口的大小如何告知對(duì)方
Client向Server發(fā)送數(shù)據(jù),Server收到報(bào)文會(huì)應(yīng)答。應(yīng)答也是基于TCP協(xié)議通信的,必須是一個(gè)完整的TCP報(bào)文(可以沒有數(shù)據(jù),但至少是完整的報(bào)頭)!窗口大小通過應(yīng)答報(bào)文告知Client,當(dāng)然TCP會(huì)有**捎帶應(yīng)答(Server也要發(fā)送數(shù)據(jù)捎帶的將窗口大小告知對(duì)方(數(shù)據(jù)+應(yīng)答))**的機(jī)制,有可能不會(huì)發(fā)送單獨(dú)的應(yīng)答報(bào)文。
-
序列號(hào):用來解決網(wǎng)絡(luò)包亂序問題。
-
確認(rèn)序列號(hào):表示確認(rèn)序列號(hào)之前的數(shù)據(jù),已經(jīng)全部收到,下次發(fā)送請(qǐng)從確認(rèn)序列號(hào)指定的數(shù)字開始發(fā)送。
序列號(hào)和確認(rèn)序列號(hào)的理解
TCP為了提高效率,不會(huì)串行化的傳輸數(shù)據(jù),而是Client發(fā)送一批數(shù)據(jù)給Server。那么Server無法得知報(bào)文的順序而導(dǎo)致數(shù)據(jù)包亂序的問題,而亂序本身就是一種不可靠的表現(xiàn)。所以通過序列號(hào),按序接收就能保證順序問題。
Server對(duì)Client發(fā)送而來的數(shù)據(jù)序列號(hào)+1,響應(yīng)確認(rèn)序列號(hào)。表示確認(rèn)序列號(hào)之前的數(shù)據(jù),已經(jīng)全部收到,什么意思呢,如:Server響應(yīng)2001表示前面發(fā)送的2000個(gè)字節(jié)的數(shù)據(jù)都收到了,所以允許1001應(yīng)答報(bào)文丟失。確認(rèn)序列號(hào)允許少量的應(yīng)答報(bào)文丟失(這里不攜帶數(shù)據(jù)),如果是數(shù)據(jù)丟失會(huì)有重傳的機(jī)制。
當(dāng)然序列號(hào)的初始值,是在建立連接時(shí)由計(jì)算機(jī)生成的隨機(jī)數(shù)作為其初始值,通過 SYN 包傳給接收端主機(jī),每發(fā)送一次數(shù)據(jù),就「累加」一次該「數(shù)據(jù)字節(jié)數(shù)」的大小。
HTTP中會(huì)定義一個(gè)用戶級(jí)的緩沖區(qū),想象成一個(gè)大數(shù)組。系列號(hào)會(huì)根據(jù)數(shù)組的下標(biāo)來確定會(huì)更好理解。
-
6個(gè)標(biāo)記位:區(qū)分TCP報(bào)文的類型
TCP通信需要建立連接,建立完成之后才是正常通信,通信完畢后會(huì)斷開連接。**不要扯什么,無論是建立連接的報(bào)文、正常通信的報(bào)文、還是斷開連接的報(bào)文,都是一個(gè)完整的TCP報(bào)文!**如何區(qū)分是哪種類型的報(bào)文呢,這就可以根據(jù)報(bào)文中的標(biāo)記位來區(qū)分。
-
SYN:設(shè)為
1
時(shí),表示希望建立連接(稱為同步報(bào)文段),并在其「序列號(hào)」的字段進(jìn)行序列號(hào)初始值的設(shè)定 -
ACK:設(shè)為
1
時(shí),「確認(rèn)應(yīng)答」的字段變?yōu)橛行?;TCP 規(guī)定除了最初建立連接時(shí)的SYN
包之外該位必須設(shè)置為1
。 -
FIN :設(shè)為
1
時(shí),表示今后不會(huì)再有數(shù)據(jù)發(fā)送,希望斷開連接。 -
RST : 設(shè)為
1
時(shí),對(duì)方要求重新建立連接; 把攜帶RST標(biāo)識(shí)的稱為復(fù)位報(bào)文段 -
PSH:設(shè)為
1
時(shí),提示接收端應(yīng)用程序立刻從TCP緩沖區(qū)把數(shù)據(jù)讀走。Client一直向服務(wù)器發(fā)送數(shù)據(jù),有可能服務(wù)器,很繁忙沒來得及讀取接收緩存的內(nèi)容,PSH字段提示接收端應(yīng)用程序立刻從TCP緩沖區(qū)把數(shù)據(jù)讀走;但如果有一個(gè)極端,應(yīng)用程序就沒有讀取數(shù)據(jù)的方法,那這不扯了嗎,要設(shè)計(jì)一個(gè)程序通信,結(jié)果又不讀取數(shù)據(jù),這像什么話??!
-
-
URG:設(shè)為
1
時(shí),緊急指針有效Server服務(wù)器負(fù)載過大,無法處理Client發(fā)來的普通報(bào)文,因?yàn)閳?bào)文需要按序排隊(duì)。但又想知道Server在處理什么工作,可以在編碼時(shí)設(shè)置MSG_OOB(如:1表示IO操作)這樣的屬性,然后將URG設(shè)置為1,讓這個(gè)報(bào)文的緊急字段指向的數(shù)據(jù)有效,插隊(duì)處理。
16位緊急指針字段表示緊急數(shù)據(jù)的首地址,緊急數(shù)據(jù)不能太大,一般是首地址往后的1個(gè)字節(jié)
3.TCP的三次握手和四次揮手
3.1.TCP的握手過程
這個(gè)地方參照的是小林哥的博客
- 一開始,客戶端和服務(wù)端都處于
CLOSE
狀態(tài)。先是服務(wù)端主動(dòng)監(jiān)聽某個(gè)端口,處于LISTEN
狀態(tài)。 - 客戶端會(huì)隨機(jī)初始化序號(hào)(
client_isn
),將此序號(hào)置于 TCP 首部的「序號(hào)」字段中,同時(shí)把SYN
標(biāo)志位置為1
,表示SYN
報(bào)文。接著把第一個(gè) SYN 報(bào)文發(fā)送給服務(wù)端,表示向服務(wù)端發(fā)起連接,該報(bào)文不包含應(yīng)用層數(shù)據(jù),之后客戶端處于SYN-SENT
狀態(tài)。 - 服務(wù)端收到客戶端的
SYN
報(bào)文后,首先服務(wù)端也隨機(jī)初始化自己的序號(hào)(server_isn
),將此序號(hào)填入 TCP 首部的「序號(hào)」字段中,其次把 TCP 首部的「確認(rèn)應(yīng)答號(hào)」字段填入client_isn + 1
, 接著把SYN
和ACK
標(biāo)志位置為1
。最后把該報(bào)文發(fā)給客戶端,該報(bào)文也不包含應(yīng)用層數(shù)據(jù),之后服務(wù)端處于SYN-RCVD
狀態(tài)。 - 客戶端收到服務(wù)端報(bào)文后,還要向服務(wù)端回應(yīng)最后一個(gè)應(yīng)答報(bào)文,首先該應(yīng)答報(bào)文 TCP 首部
ACK
標(biāo)志位置為1
,其次「確認(rèn)應(yīng)答號(hào)」字段填入server_isn + 1
,最后把報(bào)文發(fā)送給服務(wù)端,這次報(bào)文可以攜帶客戶到服務(wù)端的數(shù)據(jù),之后客戶端處于ESTABLISHED
狀態(tài)。 - 服務(wù)端收到客戶端的應(yīng)答報(bào)文后,也進(jìn)入
ESTABLISHED
狀態(tài)。
總結(jié)
任何一個(gè)網(wǎng)絡(luò)協(xié)議都無法保證100%的可靠性!TCP建立連接的時(shí)候最后一個(gè)ACK應(yīng)答,沒有沒有應(yīng)答的,如果有應(yīng)答有應(yīng)答,那就衍生了雞生蛋蛋生雞的問題。但是三次握手能保證局部的可靠性。
為什么是三次握手?不是兩次?四次?
首要原因是為了防止舊的重復(fù)連接初始化造成混亂
客戶端先發(fā)送了 SYN(seq = 90)報(bào)文,然后客戶端宕機(jī)了,而且這個(gè) SYN 報(bào)文還被網(wǎng)絡(luò)阻塞了,服務(wù)端并沒有收到,接著客戶端重啟后,又重新向服務(wù)端建立連接,發(fā)送了 SYN(seq = 100)報(bào)文(注意!不是重傳 SYN,重傳的 SYN 的序列號(hào)是一樣的)
其實(shí),三次握手服務(wù)器最后才進(jìn)入ESTABLISHED,通過這樣奇數(shù)次連接的方式,如果建立過程中的報(bào)文丟失,都可以將失敗的成本嫁接到客戶端。 另外三次握手保證了通信的全雙工驗(yàn)證,保證通信的局部可靠,還有就是可以同步雙方初始序列號(hào)等。
無論是一次還是兩次,客戶端向服務(wù)端請(qǐng)求連接,SYN到達(dá)服務(wù)器就立馬ESTABLISHED狀態(tài),服務(wù)器需要?jiǎng)?chuàng)建對(duì)應(yīng)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)維持連接,有明顯的SYN洪水的問題。文章來源:http://www.zghlxwxcb.cn/news/detail-842915.html
而為什么不是四次,其實(shí)也可以是四次,但是TCP有捎帶應(yīng)答的機(jī)制,服務(wù)器向客戶端發(fā)送SYN時(shí)捎帶了ACK。說白了三次握手的最小次數(shù)的連接。文章來源地址http://www.zghlxwxcb.cn/news/detail-842915.html
到了這里,關(guān)于TCP | TCP協(xié)議格式 | 三次握手的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!