較長的描述了 tcp 協定的連接配接和關閉的整個過程。解釋了為什麼 tcp 協定是面向連接配接的、可靠的資料傳輸協定。
在網際網路上之間的通信交流,一般是基于 tcp (transmission control protocol,傳輸控制協定) 或者 udp (user datagram protocol,使用者資料報協定) 。兩者的一個重要差別是,tcp 是面向連接配接提供端到端可靠的資料流(flow of data)。
“面向連接配接”就是在正式通信前必須要與對方建立起連接配接。比如你給别人打電話,必須等線路接通了、對方拿起話筒才能互相通話。
tcp 是基于連接配接的協定,也就是說,在正式收發資料前,必須和對方建立可靠的連接配接。一個 tcp 連接配接必須要經過三次“握手”才能建立起來,簡單的講就是:
為了建立連接配接時,用戶端 a 發送 syn 包(syn=j)到伺服器 b,并進入 syn_send狀态,等待伺服器 b 确認。 【a 向 b 請求連接配接:“我想給你發資料,可以嗎?”】
伺服器 b 收到 syn 包,必須确認用戶端 a 的 syn(ack=j+1),同時自己也發送一個 syn 包(syn=k),即 syn+ack 包,此時伺服器b進入syn_recv 狀态。 【b 回應 a:“好的,你來吧”】
用戶端 a 收到伺服器 b 的 syn+ack 包,向伺服器 b 發送确認包 ack(ack=k+1),此包發送完畢,用戶端 a 和伺服器 b 進入 established 狀态,完成三次握手。 【a 回應 b:“好的,我來也,你接着吧!”】
三次“握手”的目的是使資料包的發送和接收同步,經過三次“對話”之後,主機 a 才向主機 b 正式發送資料。

由于 tcp 連接配接是全雙工的,是以每個方向都必須單獨進行關閉。這個原則是當一方完成它的資料發送任務後就能發送一個 fin 來終止這個方向的連接配接。收到一個 fin 隻意味着這一方向上沒有資料流動,一個 tcp 連接配接在收到一個 fin 後仍能發送資料。首先進行關閉的一方将執行主動關閉,而另一方執行被動關閉。
用戶端 a 發送一個 fin 給伺服器 b,用來關閉用戶端 a 到伺服器 b 的資料傳送。【a 對 b 說:“我傳完了”】
伺服器 b 收到這個 fin,它發回一個 ack,确認序号為收到的序号加1(封包段5)。和 syn 一樣,一個 fin 将占用一個序号。 【b 回應 a:“好的”】
伺服器 b 關閉與用戶端 a 的連接配接,發送一個 fin 給用戶端 a。 【b 對 a 說:“我也傳完了”】
用戶端 a 發回 ack 封包确認,并将确認序号設定為收到序号加1。 【a回應b:“好的,我走了”】
tcp 采用四次分手關閉連接配接如圖2所示。
這是因為服務端的 listen 狀态下的 socket 當收到 syn 封包的建連請求後,它可以把 ack 和 syn(ack起應答作用,而syn起同步作用)放在一個封包裡來發送。但關閉連接配接時,當收到對方的 fin 封包通知時,它僅僅表示對方沒有資料發送給你了;但未必你所有的資料都全部發送給對方了,是以你可以未必會馬上會關閉socket,也即你可能還需要發送一些資料給對方之後,再發送 fin 封包給對方來表示你同意現在可以關閉連接配接了,是以它這裡的 ack 封包和 fin 封包多數情況下都是分開發送的。 【收到2個“好的”才算完成。大家好才是真的好】
這是因為雖然雙方都同意關閉連接配接了,而且握手的4個封包也都協調和發送完畢,按理可以直接回到 closed 狀态(就好比從 syn_send 狀态到 establish 狀态那樣);但是因為我們必須要假想網絡是不可靠的,你無法保證你最後發送的ack封包會一定被對方收到,是以對方處于 last_ack 狀态下的 socket 可能會因為逾時未收到 ack 封包,而重發 fin 封包,是以這個 time_wait 狀态的作用就是用來重發可能丢失的 ack 封包
syn: 同步序列編号(synchronize sequence numbers)
ack: 确認字段
fin: 發送方已經傳完資料
psh: 推送功能
rst: 重置連接配接
urg: 緊急指針