傳輸層(一)UDP協議與TCP協議

傳輸層是整個網絡體系結構中的關鍵層次之一,主要負責向兩個主機中進程之間的通信提供服務。由於一個主機同時運行多個進程,因此運輸層具有有複用和分用功能。傳輸層在終端用戶之間提供透明的數據傳輸,向上層提供可靠的數據傳輸服務。傳輸層在給定的鏈路上通過流量控制、分段/重組和差錯控制來保證數據傳輸的可靠性。傳輸層的一些協議是面向鏈接的,這就意味着傳輸層能保持對分段的跟蹤,並且重傳那些失敗的分段。

傳輸層負責端對端的傳輸,不論是TCP協議還是UDP協議都是和端口有着聯繫

端口號

端口的劃分:uint16_t (0~2^16)

  • 知名端口

http:80
https:443
ssh服務:22
ftp服務:21
Telnet服務:23

  • 非知名端口

mysql:3306
oracle:1521

知名端口的查看

cat /etc/services

傳輸層UDP協議

  • 特點

無連接,不可靠,面向數據報

無連接:知道端口的ip和端口號就可以直接進行傳輸,不需要建立連接
不可靠:沒有確認應答和重傳機制。如果數據在傳輸的過程中發生丟失,UDP協議也不會給應用層返回任何錯誤的信息
面向數據報:對於信息只能整條發送與整條接收,不會存在兩條數據並存在緩衝區中。也就不存在粘包問題

  • UDP協議的報頭

源端口(2字節)+ 目的端口(2字節)+ 數據長度(最大可表示的字節數2^16 – 65536)+ 校驗和
在這裏插入圖片描述

網絡抓包

  • 抓包的命令
sudo tcpdump -i any port 19999 -s 0 -w 1.dat

然後在Windows下的wireshark中打開後:
在這裏插入圖片描述
可以看到只有數據發送的過程,沒有連接

數據長度

uint16_t:最大的數值是65536,也就是說UDP協議單次傳輸的數據最大長度時65536個字節
UDP協議在傳輸數據的時候,不會出現粘包問題的,因爲他的收發緩衝區一次只能存在一條數據

  • 一次傳輸的數據小於65536時,選擇直接傳送就可以了
  • 當一次傳輸的數據大於65536時,就需要在應用層進行拆分,向數據分爲小於65536的幾部分,然後按照順序依次發送給對端即可

當應用層一次需要傳輸的數據大於2^16時,我們就需要在應用層進行分片傳輸。就是說在應用層的時候,就將大於2 ^16的數據進行拆分,分多次使用UDP協議進行傳輸
在這裏插入圖片描述
因爲UDP協議的特性是面向數據報,數據都是整條整條的傳輸,所以在拆分後認爲應用層傳輸的每一條數據都是一個完整的UDP數據報

所以說,對於接受端接受UDP數據的進程而言,從協議棧中的傳輸層中的UDP接受的數據可能並不是一個完整的數據。爲了解決數據傳輸不完整的問題,數據發送雙方需要在應用層的時候就定製自定義協議,標識着應用層數據的長度和判斷數據是否完整
在這裏插入圖片描述

校驗和

因爲UDP協議在傳輸數據的時候可能存在丟失的情況,所以就用校驗和來判斷UDP數據在傳輸的過程中是否發生損壞

  • 發生損壞,直接丟棄數據報,不會傳遞給應用層
  • 沒有損壞,在應用層調用recvfrom的時候,將數據報提交給應用層

校驗和的計算

將UDP的數據報分成多個16位的數據,除了檢驗和不進行相加外,其他數據進行加運算
僞頭部(源IP + 目的IP + UDP的協議號(17) + 數據長度)+ UDP頭部(源端口 + 目的端口 + 數據長度) + 所有需要發送的數據

在這裏插入圖片描述
在計算的時候,因爲都是16位的數據進行相加,所有很容易出現溢出的情況,這個時候就需要進行回捲

因爲兩個16位的數據進行相加,最多隻能溢出一位,就變成了17位數據。那麼回捲就是把這個17位的數據分成最高位 + 低16位兩部分,再把這兩部分進行相加,這就是新的結果
在這裏插入圖片描述
在計算校驗和的時候,就是把所有加起來的結果進行反碼運算,最後這個反碼運算的結果就是16位的校驗和。

所以說,校驗和 和 其他所有數據相加的結果就是 FFFF

UDP緩衝區

  1. 緩衝區中對應應用層的數據,都是整條發送與整條接收的
  2. 對於發送而言,應用層先使用sendto接口將數據提交到傳輸層的UDP發送緩衝區中,然後打上UDP協議的報頭,就可以直接交給網絡層進行下一步傳輸了
  3. 對於接收而言,應用層使用recvfrom接口將數據從傳輸層的接收緩衝區中拷貝到應用層,UDP接收緩衝區不保證數據的有序到達,也不保證可靠性;
  4. 當接收緩衝區滿的時候,從網卡中接收的UDP數據報就會被丟棄,然後內核會返回一個EMSGSIZE錯誤

UDP的應用

DNS,域名解析協議。將域名轉換爲IP地址的時候,使用UDP協議

TCP協議

  • 特點

面向連接,可靠的傳輸,面向字節流

面向連接:使用TCP協議進行通信的雙方在通信之前必須建立連接,然後纔可以進行通信。TCP連接是一個全雙工的,也就是通信雙方可以互相進行發送和接收數據。(三次握手)

可靠的傳輸:TCP協議有一個確認應答與超時重傳的機制,當數據在傳輸的過程中丟失的話,對端就不會進行確認,等到一個時間段後發送端就會重新發送這個數據。

面向字節流:發送端與接收端進行讀寫數據之間沒有任何數量關係,發送端多次待發送的數據可以一起放在發送緩衝區中,接收端可以一下全部接受

在這裏插入圖片描述

  • TCP協議段格式

在這裏插入圖片描述
源/目的端口號:表示數據從哪裏來,到哪裏去

32位序號/32位確認號:確認應答機制

4位TCP報頭長度:表示TCP的頭部有多少個32位數據(四個字節),所以TCP頭部的最大長度時 15 * 4 = 60

6個標誌位

  • URG:緊急指針是否有效
  • ACK:確認號是否有效
  • PSH:提示接收端應用程序立刻從TCP緩衝區把數據讀走
  • RST:對方要求重新建立連接,攜帶RST標識的稱爲復位報文段
  • SYN:請求建立連接,攜帶SYN標識的稱爲同步報文段
  • FIN:通知對方,這個端口要關閉了,稱攜帶FIN標識的稱爲結束報文

16位窗口大小:兩個字節數據,窗口表示的範圍0~2^16

16爲校驗和:檢驗數據是否傳輸完成

16位緊急指針:和URG標誌位一起來使用,如果URG標誌位爲1,則緊急指針指向的數據有效

40字節頭部選項:MSS–》最大報文段長度

網絡抓包

在這裏插入圖片描述
TCP連接的通信雙方,在通信之前進行三次握手的請求連接,通信完畢之後進行四次揮手關閉連接

三次握手

有一個概念就是客戶端與服務端是相對的,而不是絕對的。我們認爲的時候,率先發起連接的一方稱爲客戶端,被動連接的一方稱爲服務端。

三次握手的前提就是連接方與被動連接方都完成了前期的準備工作
在這裏插入圖片描述
接下來就是三次握手的過程,這個過程就是一個確認應答的階段

  1. 客戶端率先發起連接請求,向服務端發送SYN報文
  2. 服務端在收到SYN報文後,向客戶端回覆ACK + SYN報文。其中,ACK報文是告訴客戶端:服務端收到了你發送的信息,至於是發送的哪一個請求,就是後面跟着的SYN報文
  3. 客戶端收到了服務端發送的確認收到報文的請求,並回復服務端自己收到的請求,發送一個ACK報文

在這裏插入圖片描述

四次揮手

通信雙方通信,那麼肯定就有通信結束的時候。又因爲TCP協議是面向連接的,所以在結束的時候不能一句話不說,悄悄就走了,這讓對方情何以堪?

四次揮手,肯定也是四個階段,因爲可能是服務端先給客戶端發起斷開請求,也可能是客戶端先給服務端發起斷開請求。

所以發起請求的一方稱爲主動斷開連接的一方,另一方就是對端,也就是被動斷開連接的一方

  1. 主動斷開連接的一方,率先給對端發送一個FIN報文,表示自己不想聊了,要退出了
  2. 對端在收到FIN報文後,向主動斷開連接的一方發送ACK報文,表名自己收到了你想要退出的消息
  3. 緊接着對端向主動斷開連接的一方也發送一個FIN報文,既然你不想聊了,我也不想聊了,表示自己也要退出了
  4. 主動斷開連接方先收到對端的ACK報文,這個時候還不能退出,因爲不確定對端是否還有話要說。
    然後收到了對端的FIN報文,知道了對端也要退出,就給對端發送一個ACK確認的報文,告訴對端,我知道你退出了

在這裏插入圖片描述
到了這裏,其實四次揮手還不算完,爲什麼呢?這個時候主動斷開連接方還需要考慮,自己發送給對端的ACK報文,對方有沒有收到?
在這裏插入圖片描述

MSL,最大報文段生存時間,指的是發送方認爲TCP報文在網絡中最大的生存時間,一般是60s

  • 查看MSL的命令
cat /proc/sys/net/ipv4/tcp_fin_timeout

在這裏插入圖片描述
等待兩個MSL,就是爲了防止發送方給對端發送的ACK確認退出報文,在途中因爲各種原因丟失的情況。

這個時候給了發送方一個重新發送的機會,假設ACK報文發生了丟失

  1. 第一個MSL,這時對端因爲還沒有收到發送方的ACK報文,自己還處於LASK_ACK的狀態,於是就再次給發送方發送一個FIN退出的報文,告訴自己要走了
  2. 第二個MSL,這時發送方又收到了對方的FIN報文,知道自己剛纔那個ACK報文丟失了,就再給對方發一個ACK報文,好讓對方退出

這個時候,如果第二次的ACK報文沒有發生丟失,對端在收到ACK報文後,就進入了CLOSED狀態。發送方在第二個MSL結束後就會進入CLOSED狀態。

而如果又發生了丟失。。。。。這時發送方和對端因爲2MSL已經結束了,就進入了CLOSED狀態

2MSL == 丟失ACK的MSL + 重傳FIN的MSL

由2MSL引起的地址複用問題

如果一個TCP協議的程序,他的主動斷開連接的一方是服務端,那麼在服務端斷開連接之後,立刻重新連接的時候,就會發現該端口處於bind error: Address already in use的狀態,如下所示:
在這裏插入圖片描述
問題的根源:
就是因爲我們直接退出了服務端,使得服務端所佔有的端口沒有變成CLOSE狀態,而是TIME_WAIT的狀態

我們的服務端率先斷開了連接,在連接斷開的時候,就有一個TIME_WAIT的狀態,他需要等待2MSL的時間。

這個行爲是傳輸層TCP的行爲,即使我們的應用程序已經退出掉了,但是內核中對應的19999端口還是被佔用的

同理,當我們的客戶端端口後,客戶端的進程也屬於一個TIME_WAIT的狀態,但是進程號是隨機的。。。我們服務端的端口號是固定的,所以客戶端先斷開連接後影響比較小。
在這裏插入圖片描述
解決地址複用的函數接口

#include <sys/types.h>          
#include <sys/socket.h>

int setsockopt(int sockfd, int level, int optname,
       const void *optval, socklen_t optlen);
  • sockfd:將要被設置的套接字
  • level:指定套接字的層次,他的取值有三種
SOL_SOCKET:通用套接字選項 --》地址複用
IPPROTO_TCP:TCP選項
IPPROTO_IP:IP選項
  • optname:在level中要完成的任務
SOL_SOCKET -->
	SO_REUSERADDR:允許重用本地地址和端口
	SO_RECVBUF:獲取接收緩衝區的大小
IPPROTO_TCP -->
	TCP_MAXSEG:獲取TCP最大數據段的大小
IPPROTO_IP -->
	IP_TTL:獲取最大字節數,也就是最大生存空間
  • optval:需要完成的任務,地址複用–》傳入1。傳入的是一個 變量的地址
int i = 1;
&i;
  • len:optval的長度

然後在創建套接字的同時,加上地址複用的函數
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章