tcp(transmission control protocol,傳輸控制協議)是一種面向連線的、可靠的、基於位元組流的通訊協議,資料在傳輸前要建立連線,傳輸完畢後還要斷開連線。
客戶端在收發資料前要使用 connect() 函式和伺服器建立連線。建立連線的目的是保證ip位址、埠、物理鏈路等正確無誤,為資料的傳輸開闢通道。
tcp三次握手(建立連線)
tcp建立連線時要傳輸三個資料報,俗稱三次握手。
tcp資料報的結構:
其中有幾個字段比較重要,需要說明一下:
1)32位的序列號(seq):用來標識從計算機a傳送到計算機b的資料報的序號,計算機傳送資料時對此進行標記。
2)32位確認號(ack):客戶端和伺服器端都可以傳送,ack = seq + 1
3)標誌位:
urg:緊急指標(urgent pointer)有效。
ack:確認序號有效。
psh:接收方應該盡快將這個報文交給應用層。
rst:重置連線。
syn:建立乙個新連線。
fin:斷開乙個連線。
三個報文段就是圖中中間的前三個。
在建立連線之前,伺服器開始處於被動監聽狀態,客戶端處於關閉狀態。
1)當客戶端呼叫 connect() 函式後,tcp協議會組建乙個資料報,並設定 syn 標誌位,表示該資料報是用來建立同步連線的。同時生成乙個隨機數字 1000,填充「序號(seq)」字段,(報文段1)表示該資料報的序號。完成這些工作,開始向伺服器端傳送資料報,客戶端就進入了syn-send狀態。
2)伺服器端收到資料報,檢測到已經設定了 syn 標誌位,就知道這是客戶端發來的建立連線的「請求包」。伺服器端也會組建乙個資料報,並設定 syn 和 ack 標誌位,syn 表示該資料報用來建立連線,ack 用來確認收到了剛才客戶端傳送的資料報。伺服器生成乙個隨機數 2000,填充「序號(seq)」字段。(報文2)2000 和客戶端資料報沒有關係。伺服器將資料報發出,進入syn-recv狀態。
3)客戶端收到資料報,檢測到已經設定了 syn 和 ack 標誌位,就知道這是伺服器發來的「確認包」。客戶端會檢測「確認號(ack)」字段,看它的值是否為 1000+1,如果是就說明連線建立成功。
接下來,客戶端會繼續組建資料報,並設定 ack 標誌位,表示客戶端正確接收了伺服器發來的「確認包」。同時,將剛才伺服器發來的資料報序號(2000)加1,得到 2001,(報文3)並用這個數字來填充「確認號(ack)」字段。
客戶端將資料報發出,進入establised狀態,表示連線已經成功建立。
4)伺服器端收到資料報,檢測到已經設定了 ack 標誌位,就知道這是客戶端發來的「確認包」。伺服器會檢測「確認號(ack)」字段,看它的值是否為 2000+1,如果是就說明連線建立成功,伺服器進入establised狀態。
至此,客戶端和伺服器都進入了establised狀態,連線建立成功,接下來就可以收發資料了
建立連線非常重要,它是資料正確傳輸的前提;斷開連線同樣重要,它讓計算機釋放不再使用的資源。如果連線不能正常斷開,不僅會造成資料傳輸錯誤,還會導致套接字不能關閉,持續占用資源,如果併發量高,伺服器壓力堪憂。
建立連線需要三次握手,斷開連線需要四次握手,可以形象的比喻為下面的對話:
[shake 1] 套接字a:「任務處理完畢,我希望斷開連線。」
[shake 2] 套接字b:「哦,是嗎?請稍等,我準備一下。」
等待片刻後……
[shake 3] 套接字b:「我準備好了,可以斷開連線了。」
[shake 4] 套接字a:「好的,謝謝合作。」
建立連線後,客戶端和伺服器都處於establised狀態。這時,客戶端發起斷開連線的請求:
客戶端呼叫 close() 函式後,向伺服器傳送 fin 資料報,進入fin_wait_1狀態。fin 是 finish 的縮寫,表示完成任務需要斷開連線。
伺服器收到資料報後,檢測到設定了 fin 標誌位,知道要斷開連線,於是向客戶端傳送「確認包」,進入close_wait狀態。
注意:伺服器收到請求後並不是立即斷開連線,而是先向客戶端傳送「確認包」,告訴它我知道了,我需要準備一下才能斷開連線。
客戶端收到「確認包」後進入fin_wait_2狀態,等待伺服器準備完畢後再次傳送資料報。
等待片刻後,伺服器準備完畢,可以斷開連線,於是再主動向客戶端傳送 fin 包,告訴它我準備好了,斷開連線吧。然後進入last_ack狀態。
客戶端收到伺服器的 fin 包後,再向伺服器傳送 ack 包,告訴它你斷開連線吧。然後進入time_wait狀態。
伺服器收到客戶端的 ack 包後,就斷開連線,關閉套接字,進入closed狀態。
關於 time_wait 狀態的說明
客戶端最後一次傳送 ack包後進入 time_wait 狀態,而不是直接進入 closed 狀態關閉連線,這是為什麼呢?
tcp 是面向連線的傳輸方式,必須保證資料能夠正確到達目標機器,不能丟失或出錯,而網路是不穩定的,隨時可能會毀壞資料,所以機器a每次向機器b傳送資料報後,都要求機器b」確認「,回傳ack包,告訴機器a我收到了,這樣機器a才能知道資料傳送成功了。如果機器b沒有回傳ack包,機器a會重新傳送,直到機器b回傳ack包。
客戶端最後一次向伺服器回傳ack包時,有可能會因為網路問題導致伺服器收不到,伺服器會再次傳送 fin 包,如果這時客戶端完全關閉了連線,那麼伺服器無論如何也收不到ack包了,所以客戶端需要等待片刻、確認對方收到ack包後才能進入closed狀態。那麼,要等待多久呢?
資料報在網路中是有生存時間的,超過這個時間還未到達目標主機就會被丟棄,並通知源主機。這稱為報文最大生存時間(msl,maximum segment lifetime)。time_wait 要等待 2msl 才會進入 closed 狀態。ack 包到達伺服器需要 msl 時間,伺服器重傳 fin 包也需要 msl 時間,2msl 是資料報往返的最大時間,如果 2msl 後還未收到伺服器重傳的 fin 包,就說明伺服器已經收到了 ack 包。
TCP資料的傳輸過程
建立連線後,兩台主機就可以相互傳輸資料了。如下圖所示 上圖給出了主機a分2次 分2個資料報 向主機b傳遞200位元組的過程。首先,主機a通過1個資料報傳送100個位元組的資料,資料報的 seq 號設定為 1200。主機b為了確認這一點,向主機a傳送 ack 包,並將 ack 號設定為 1301。為了...
TCP資料的傳輸過程
tcp資料的傳輸過程建立連線後,兩台主機就可以相互傳輸資料了。如下圖所示 上圖給出了主機a分2次 分2個資料報 向主機b傳遞200位元組的過程。首先,主機a通過1個資料報傳送100個位元組的資料,資料報的 seq 號設定為 1200。主機b為了確認這一點,向主機a傳送 ack 包,並將 ack 號設...
TCP協議傳輸過程
引入動態套接字的庫檔案 include include include void main if listensocket socket af inet,sock stream,ipproto tcp invalid socket 建立套接字 serveraddr.sin family af ine...