介紹
? ? TCP是一個面向連接的協(xié)議,所以在連接雙方發(fā)送數(shù)據(jù)之前,都需要先建立一條連接。這和IP協(xié)議,IMCP協(xié)議完全不同阐肤。IP協(xié)議,IMCP協(xié)議都只是發(fā)送數(shù)據(jù)而已,大多數(shù)都不關(guān)心發(fā)送的數(shù)據(jù)是不是送到讲坎,UDP協(xié)議尤其明顯孕惜,因為UDP都不用考慮數(shù)據(jù)分片。
正文
?首先介紹TCP包(如圖1)晨炕,然后通過TCP包來了解它的連接和中止過程衫画。
上圖中的字段需要重點介紹一下:
(1)源端口、目標端口:計算機上的進程要和其他進程通信是要通過計算機端口的瓮栗,而一個計算機端口某個時刻只能被一個進程占用削罩,所以通過指定源端口和目標端口,就可以知道是哪兩個進程需要通信费奸。源端口弥激、目標端口是用16位表示的,可推算計算機的端口個數(shù)為2^16個
(2)序號:Seq序號愿阐,占32位微服,用來標識從TCP源端向目的端發(fā)送的字節(jié)流,發(fā)起方發(fā)送數(shù)據(jù)時對此進行標記换况。
(3)確認號:Ack序號职辨,占32位盗蟆,只有ACK標志位為1時戈二,確認序號字段才有效舒裤,Ack=Seq+1。也就是告訴發(fā)送發(fā):我希望你(指發(fā)送方)下次發(fā)送的數(shù)據(jù)的第一個字節(jié)數(shù)據(jù)的編號是這個確認號觉吭。
(4)數(shù)據(jù)偏移:表示TCP報文段的首部長度腾供,共4位,它指出TCP報文段的數(shù)據(jù)起始處離距離TCP報文段的起始處有多遠鲜滩。
(5)標志位:共6個伴鳖,即URG、ACK徙硅、PSH榜聂、RST、SYN嗓蘑、FIN等须肆,具體含義如下:
A、URG:緊急指針(urgent pointer)桩皿,只有當URG=1時才有效豌汇。
B、ACK:確認序號有效泄隔,只有當ACK=1時拒贱,前面的確認序號才有效。
C佛嬉、PSH:接收方應該盡快將這個數(shù)據(jù)交給應用層逻澳,為接收后續(xù)數(shù)據(jù)騰出空間。如果結(jié)果為1暖呕,則表示對方應當立即把數(shù)據(jù)提交給應用層赡盘,而不是緩存,如果不收走數(shù)據(jù)缰揪,就會一直停留在TCP接收緩沖區(qū)陨享。
D、RST:重新連接钝腺。如果收到RST=1的報文抛姑,說明與主機連接出現(xiàn)了嚴重錯誤,必須釋放連接艳狐,然后重新建立連接定硝。
E、SYN:發(fā)起一個新的連接毫目。當SYN=1蔬啡,ACK=0時诲侮,這是一個請求建立連接的報文段;當SYN=1箱蟆,ACK=1時沟绪,表示對方同意建立連接。
F空猜、FIN:釋放一個連接绽慈。當FIN=1,即告訴對方:“我的數(shù)據(jù)已發(fā)送完畢辈毯,你可以釋放連接了”坝疼。
(6)窗口大小:從本報文段的確認號開始允許對方發(fā)送的數(shù)據(jù)量谆沃。
(7)校驗和:提供額外的可靠性钝凶。
(8)緊急指針:標記緊急數(shù)據(jù)在數(shù)據(jù)字段中的位置。
(9)選項部分:其最大長度可根據(jù)TCP首部長度進行推算唁影。
需注意的是:
①耕陷、不要將確認序號Ack與標志位中的ACK搞混淆;
②夭咬、確認方Ack=發(fā)起方Req+1啃炸,兩端配對。
結(jié)束了對TCP包的首部了解卓舵,現(xiàn)在我們開始進行TCP的連接和中止南用。簡單來說TCP連接的建立可以稱為三次握手,而連接的中止則可以叫做四次揮手掏湾。
三次握手
? ? 所謂三次握手即建立TCP連接裹虫,就是指建立一個TCP連接時,需要客戶端和服務端總共發(fā)送3個包以確認連接的建立融击。在socket編程中筑公,這一過程由客戶端執(zhí)行connect來觸發(fā),整個流程如下圖所示:
過程:
(1)第一次握手:Client將標志位SYN置為1尊浪,隨機產(chǎn)生一個值seq=x匣屡,并將該數(shù)據(jù)包發(fā)送給Server,Client進入SYN_SENT狀態(tài)拇涤,等待Server確認捣作。
(2)第二次握手:Server收到數(shù)據(jù)包后由標志位SYN=1知道Client請求建立連接,Server將標志位SYN和ACK都置為1鹅士,ack=x+1券躁,隨機產(chǎn)生一個值seq=y,并將該數(shù)據(jù)包發(fā)送給Client以確認連接請求,Server進入SYN_RCVD狀態(tài)也拜。
(3)第三次握手:Client收到確認后以舒,檢查ack是否為y+1,ACK是否為1慢哈,如果正確則將標志位ACK置為1蔓钟,ack=y+1,并將該數(shù)據(jù)包發(fā)送給Server岸军,Server檢查ack是否為y+1奋刽,ACK是否為1瓦侮,如果正確則連接建立成功艰赞,Client和Server進入ESTABLISHED狀態(tài),完成三次握手肚吏,隨后Client與Server之間可以開始傳輸數(shù)據(jù)了方妖。
狀態(tài)切換:
客戶端:
Closed--> SYN-SENT --> ESTAB-LISHED
關(guān)閉----> 同步已發(fā)送 --> 已建立連接
服務器端:
Closed--> LISTEN --> SYN-RCVD --> ESTAB-LISHED
關(guān)閉---->? 收聽? --> 同步收到 --> 已建立連接
簡單來說就是:在建立連接的時候,客戶端首先向服務器申請打開某一個端口(用SYN段等于1的TCP報文)罚攀,然后服務器端發(fā)回一個ACK報文通知客戶端請求報文收到党觅,客戶端收到確認報文以后再次發(fā)出確認報文確認剛才服務器端發(fā)出的確認報文(繞口么),至此斋泄,連接的建立完成杯瞻。這就叫做三次握手。如果打算讓雙方都做好準備的話炫掐,一定要發(fā)送三次報文魁莉,而且只需要三次報文就可以了。
四次揮手
? 所謂四次揮手即終止TCP連接募胃,就是指斷開一個TCP連接時旗唁,需要客戶端和服務端總共發(fā)送4個包以確認連接的斷開。在socket編程中痹束,這一過程由客戶端或服務端任一方執(zhí)行close來觸發(fā)检疫,如下圖:
過程:
(1)第一次揮手:Client發(fā)送一個FIN,用來關(guān)閉Client到Server的數(shù)據(jù)傳送祷嘶,Client進入FIN_WAIT_1狀態(tài)屎媳。
(2)第二次揮手:Server收到FIN后,發(fā)送一個ACK給Client论巍,確認序號為收到序號+1(與SYN相同烛谊,一個FIN占用一個序號),Server進入CLOSE_WAIT狀態(tài)环壤。
(3)第三次揮手:Server發(fā)送一個FIN晒来,用來關(guān)閉Server到Client的數(shù)據(jù)傳送,Server進入LAST_ACK狀態(tài)郑现。
(4)第四次揮手:Client收到FIN后湃崩,Client進入TIME_WAIT狀態(tài)荧降,接著發(fā)送一個ACK給Server,確認序號為收到序號+1攒读,Server進入CLOSED狀態(tài)朵诫,完成四次揮手。
狀態(tài)切換:
客戶端:
ESTAB-LISHED --> FIN-WAIT-1 -- > FIN-WAIT-2 --> TIME-WAIT(等待2MSL) --> CLOSED
建立連接狀態(tài) ? ? ? ? ? ?終止等待1 ? ? ? ? 終止等待2 ? ? ? ? ? ? 時間等待? ? ? ? ? ? ? ? ? 關(guān)閉
服務器端:
ESTAB-LISHED --> CLOSE-WAIT --> LAST-ACK --> CLOSED
建立連接狀態(tài) ? ? ? ? ? ?關(guān)閉等待 ? ? ? ? ? ? ?最后確認 ? ? ? ? ?關(guān)閉
TCP的連接是全雙工(可以同時發(fā)送和接收)連接薄扁,因此在關(guān)閉連接的時候剪返,必須關(guān)閉傳和送兩個方向上的連接〉嗣罚客戶機給服務器一個FIN為1的TCP報文脱盲,然后服務器返回給客戶端一個確認ACK報文,并且發(fā)送一個FIN報文日缨,當客戶機回復ACK報文后(四次握手)钱反,連接就結(jié)束了。
上面是一方主動關(guān)閉匣距,另一方被動關(guān)閉的情況面哥,實際中還會出現(xiàn)同時發(fā)起主動關(guān)閉的情況,具體流程如下圖:
流程和狀態(tài)在上圖中已經(jīng)很明了了毅待,在此不再描述尚卫,可以參考前面的四次揮手解析步驟。
OK~是不是很難懂的感覺尸红?那我們來說的“人性化點的”吧
三次握手流程:
客戶端發(fā)個請求“開門吶吱涉,我要進來”給服務器
服務器發(fā)個“進來吧,我去給你開門”給客戶端
客戶端有很客氣的發(fā)個“謝謝驶乾,我要進來了”給服務器
四次揮手流程:
客戶端發(fā)個“時間不早了邑飒,我要走了”給服務器,等服務器起身送他
服務器聽到了级乐,發(fā)個“我知道了疙咸,那我送你出門吧”給客戶端,等客戶端走
服務器把門關(guān)上后风科,發(fā)個“我關(guān)門了”給客戶端撒轮,然后等客戶端走(哎呦喂~矯情啊)
客戶端發(fā)個“我知道了贼穆,我走了”题山,之后自己就走了
附加題:為什么建立連接是三次握手,而關(guān)閉連接卻是四次揮手呢故痊?
這是因為服務端在LISTEN狀態(tài)下顶瞳,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發(fā)送給客戶端。而關(guān)閉連接時慨菱,當收到對方的FIN報文時焰络,僅僅表示對方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),乙方也未必全部數(shù)據(jù)都發(fā)送給對方了符喝,所以乙方可以立即close闪彼,也可以發(fā)送一些數(shù)據(jù)給對方后,再發(fā)送FIN報文給對方來表示同意現(xiàn)在關(guān)閉連接协饲,因此畏腕,乙方ACK和FIN一般都會分開發(fā)送。