TCP UDP深入理解

2021-07-24 05:39:27 字數 3953 閱讀 6868

一 tcp

狀態機

closed:初始狀態。

listen:伺服器端的某個socket處於監聽狀態,可以接受連線了。

syn_rcvd: 這個狀態表示接受到了syn報文,在正常情況下,這個狀態是伺服器端的socket在建立tcp連線時的三次握手會話過程中的乙個中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了乙個客戶端測試程式,故意將三次tcp握手過程中最後乙個ack報文不予傳送。因此這種狀態時,當收到客戶端的ack報文後,它會進入到established狀態。

syn_sent: 這個狀態與syn_rcvd遙想呼應,當客戶端socket執行connect連線時,它首先傳送syn報文,因此也隨即它會進入到了syn_sent狀態,並等待服務端的傳送三次握手中的第2個報文。syn_sent狀態表示客戶端已傳送syn報文。

established:表示連線已經建立了。

fin_wait_1: 這個狀態要好好解釋一下,其實fin_wait_1和fin_wait_2狀態的真正含義都是表示等待對方的fin報文。而這兩種狀態的區別是:fin_wait_1狀態實際上是當socket在established狀態時,它想主動關閉連線,向對方傳送了fin報文,此時該socket即進入到fin_wait_1狀態。而當對方回應ack報文後,則進入到fin_wait_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ack報文,所以fin_wait_1狀態一般是比較難見到的,而fin_wait_2狀態還有時常常可以用netstat看到。

fin_wait_2:上面已經詳細解釋了這種狀態,實際上fin_wait_2狀態下的socket,表示半連線,也即有一方要求close連線,但另外還告訴對方,我暫時還有點資料需要傳送給你,稍後再關閉連線。

time_wait: 表示收到了對方的fin報文,並傳送出了ack報文,就等2msl後即可回到closed可用狀態了。如果fin_wait_1狀態下,收到了對方同時帶fin標誌和ack標誌的報文時,可以直接進入到time_wait狀態,而無須經過fin_wait_2狀態。

closing: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你傳送fin報文後,按理來說是應該先收到(或同時收到)對方的ack報文,再收到對方的fin報文。但是closing狀態表示你傳送fin報文後,並沒有收到對方的ack報文,反而卻也收到了對方的fin報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close乙個socket的話,那麼就出現了雙方同時傳送fin報文的情況,也即會出現closing狀態,表示雙方都正在關閉socket連線。

close_wait: 這種狀態的含義其實是表示在等待關閉。當對方close乙個socket後傳送fin報文給自己,你系統毫無疑問地會回應乙個ack報文給對方,此時則進入到close_wait狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有資料傳送給對方,如果沒有的話,那麼你也就可以close這個socket,傳送fin報文給對方,也即關閉連線。所以你在close_wait狀態下,需要完成的事情是等待你去關閉連線。

last_ack: 它是被動關閉一方在傳送fin報文後,最後等待對方的ack報文。當收到ack報文後,也即可以進入到closed可用狀態了

狀態過程詳解:

伺服器端首先執行listen 原語進入被動開啟狀態( listen ),等待客戶端連線;

當客戶端的乙個應用程式發出connect 命令後,本地的 tcp 實體為其建立乙個連線記錄並標記為 syn sent 狀態,然後給伺服器傳送乙個 syn 報文段;

伺服器收到乙個 syn 報文段,其 tcp 實體給客戶端傳送確認 ack 報文段同時傳送乙個 syn 訊號,進入 syn rcvd 狀態;

客戶端收到 syn +ack 報文段,其 tcp 實體給伺服器端傳送出三次握手的最後乙個 ack 報文段,並轉換為 established 狀態;

伺服器端收到確認的 ack 報文段,完成了三次握手,於是也進入 established 狀態。在此狀態下,雙方可以自由傳輸資料。

當乙個應用程式完成資料傳輸任務後,它需要關閉 tcp 連線。假設仍由客戶端發起主動關閉連線。 

客戶端執行 close ,本地的 tcp 實體傳送乙個 fin 報文段並等待響應的確認(進入狀態 fin wait 1 );

伺服器收到乙個 fin 報文段,它確認客戶端的請求發回乙個 ack 報文段,進入 close wait 狀態;

客戶端收到確認 ack 報文段,就轉移到 fin wait 2 狀態,此時連線在乙個方向上就斷開了;

伺服器端應用得到通告後,也執行 close 原語關閉另乙個方向的連線,其本地 tcp 實體向客戶端傳送乙個 fin 報文段,並進入 last ack 狀態,等待最後乙個 ack 確認報文段;

客戶端收到 fin 報文段並確認,進入 timed wait 狀態,此時雙方連線均已經斷開,但 tcp 要等待乙個 2 倍報文段最大生存時間 msl (maximum segment lifetime ),確保該連線的所有分組全部消失,以防止出現確認丟失的情況。當定時器超時後, tcp 刪除該連線記錄,返回到初始狀態( closed )。

伺服器收到最後乙個確認ack 報文段,其 tcp 實體便釋放該連線,並刪除連線記錄,返回到初始狀態( closed )。

二 tcp

建立連線的三次握手和釋放連線的四次揮手

建立連線三次握手

1)  主機a傳送乙個syn段到主機b告訴b想要連線的主機埠,以及初始的序列號(isn:x)(報文段1)

2) 主機b應答,伺服器發回包含b的初始序號的syn報文段(報文段2)作為應答。同時,將確認序號ack設定為客戶的isn加1以對a的syn報文段進行確認。

3) 主機a必須將確認序號ack設定為b的isn加1以對b的syn報文段進行確認(報文段3)

四次揮手斷開連線

1)現在的網路通訊都是基於socket實現的,當客戶端將自己的socket進行關閉時,核心協議棧會向伺服器自動傳送乙個fin置位的包,請求斷開連線。

2)伺服器端b收到請客端的fin斷開請求後,核心協議棧會立即傳送乙個ack包作為應答,表示已經收到客戶端的請求

3)伺服器執行一段時間後,關閉了自己的socket。這個時候核心協議棧會向客戶端a傳送乙個fin置位的包,請求斷開連線

4)客戶端a收到服務端b發來的fin斷開請求後,會傳送乙個ack做出應答,表示已經收到服務端的請求

為什麼建立連線協議是三次握手,而關閉連線卻是四次握手呢?

這是因為服務端的listen狀態下的socket當收到syn報文的建連請求後,它可以把ack和syn(ack起應答作用,而syn起同步作用)放在乙個報文裡來傳送。但關閉連線時,當收到對方的fin報文通知時,它僅僅表示對方沒有資料傳送給你了;但未必你所有的資料都全部傳送給對方了,所以你可以未必會馬上會關閉socket,也即你可能還需要傳送一些資料給對方之後,再傳送fin報文給對方來表示你同意現在可以關閉連線了,所以它這裡的ack報文和fin報文多數情況下都是分開傳送的。

三 tcp

資料封裝與解封

解封時,在主機b上,驅動程式從乙太網上接收到資料,然後將資料去除頭部和尾部並行crc校驗後,將正確的資料傳遞給ip層,ip層剝去ip頭,進行校驗,將資料傳送給tcp層。tcp層將tcp的頭部剝去,根據應用程式的識別符號判斷是否傳送給應用程式

udp資料封裝與解封與tcp類似

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...