建立tcp連接需要三次握手,斷開(kāi)連接需要4次。
三次握手:首先Client端發(fā)送連接請(qǐng)求報(bào)文,Server段接受連接后回復(fù)ACK報(bào)文,并為這次連接分配資源。Client端接收到ACK報(bào)文后也向Server段發(fā)生ACK報(bào)文,并分配資源,這樣TCP連接就建立了。
為什么需要三次握手?
謝希仁版《計(jì)算機(jī)網(wǎng)絡(luò)》中的例子是這樣的,“已失效的連接請(qǐng)求報(bào)文段”的產(chǎn)生在這樣一種情況下:client發(fā)出的第一個(gè)連接請(qǐng)求報(bào)文段并沒(méi)有丟失,而是在某個(gè)網(wǎng)絡(luò)結(jié)點(diǎn)長(zhǎng)時(shí)間的滯留了,以致延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)server。本來(lái)這是一個(gè)早已失效的報(bào)文段。但server收到此失效的連接請(qǐng)求報(bào)文段后,就誤認(rèn)為是client再次發(fā)出的一個(gè)新的連接請(qǐng)求。于是就向client發(fā)出確認(rèn)報(bào)文段,同意建立連接。假設(shè)不采用“三次握手”,那么只要server發(fā)出確認(rèn),新的連接就建立了。由于現(xiàn)在client并沒(méi)有發(fā)出建立連接的請(qǐng)求,因此不會(huì)理睬server的確認(rèn),也不會(huì)向server發(fā)送ack包。server卻以為新的運(yùn)輸連接已經(jīng)建立,并一直等待client發(fā)來(lái)數(shù)據(jù)。這樣,server的很多資源就白白浪費(fèi)掉了。采用“三次握手”的辦法可以防止上述現(xiàn)象發(fā)生。例如剛才那種情況,client不會(huì)向server的確認(rèn)發(fā)出確認(rèn)。server由于收不到確認(rèn),就知道client并沒(méi)有要求建立連接。在謝希仁著《計(jì)算機(jī)網(wǎng)絡(luò)》第四版中講“三次握手”的目的是“為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯(cuò)誤”。在另一部經(jīng)典的《計(jì)算機(jī)網(wǎng)絡(luò)》一書(shū)中講“三次握手”的目的是為了解決“網(wǎng)絡(luò)中存在延遲的重復(fù)分組”的問(wèn)題。這兩種不同的表述其實(shí)闡明的是同一個(gè)問(wèn)題。
那如何斷開(kāi)連接呢?簡(jiǎn)單的過(guò)程如下
1.假設(shè)客戶(hù)端主動(dòng)斷開(kāi)連接,向服務(wù)器發(fā)送fin報(bào)文,這個(gè)報(bào)文主要告訴服務(wù)器客戶(hù)端已經(jīng)沒(méi)有數(shù)據(jù)想要傳給服務(wù)器,但是服務(wù)器你如果有數(shù)據(jù)沒(méi)傳輸完的話,先不用斷開(kāi)socket連接,可以繼續(xù)發(fā)你的數(shù)據(jù),先給客戶(hù)端發(fā)ack報(bào)文。2.服務(wù)器收到報(bào)文,看了fin的報(bào)文,給客戶(hù)端發(fā)了ack報(bào)文,告訴客戶(hù)端服務(wù)器已經(jīng)收到了消息,但我還有事沒(méi)做完,讓客戶(hù)端等會(huì)。3.這時(shí)候客戶(hù)端進(jìn)入FIN_WAIT狀態(tài),即等待服務(wù)器給他發(fā)fin報(bào)文。當(dāng)服務(wù)器確定傳輸?shù)臄?shù)據(jù)都發(fā)完了,再向客戶(hù)端發(fā)送fin報(bào)文。告訴客戶(hù)端我已經(jīng)傳輸完所有數(shù)據(jù)了,可以關(guān)閉socket連接。4.客戶(hù)端收到fin報(bào)文,就知道socket要斷開(kāi)連接了,向服務(wù)器發(fā)送ack報(bào)文,但客戶(hù)端不確定這個(gè)報(bào)文是否傳到服務(wù)器了,于是進(jìn)入Time_wait狀態(tài),如果服務(wù)器沒(méi)有收到ack報(bào)文則進(jìn)行重傳,如果等待30s沒(méi)有收到消息說(shuō)明連接服務(wù)器端已經(jīng)關(guān)閉了,客戶(hù)端可以安心關(guān)閉了。這樣tcp就斷開(kāi)了。

【注意】在TIME_WAIT狀態(tài)中,如果TCP client端最后一次發(fā)送的ACK丟失了,它將重新發(fā)送。TIME_WAIT狀態(tài)中所需要的時(shí)間是依賴(lài)于實(shí)現(xiàn)方法的。典型的值為30秒、1分鐘和2分鐘。等待之后連接正式關(guān)閉,并且所有的資源(包括端口號(hào))都被釋放。
為什么連接的時(shí)候是三次握手,關(guān)閉的時(shí)候卻是四次握手?
答:因?yàn)楫?dāng)Server端收到Client端的SYN連接請(qǐng)求報(bào)文后,可以直接發(fā)送SYN+ACK報(bào)文。其中ACK報(bào)文是用來(lái)應(yīng)答的,SYN報(bào)文是用來(lái)同步的。但是關(guān)閉連接時(shí),當(dāng)Server端收到FIN報(bào)文時(shí),很可能并不會(huì)立即關(guān)閉SOCKET,所以只能先回復(fù)一個(gè)ACK報(bào)文,告訴Client端,"你發(fā)的FIN報(bào)文我收到了"。只有等到我Server端所有的報(bào)文都發(fā)送完了,我才能發(fā)送FIN報(bào)文,因此不能一起發(fā)送。故需要四步握手。