【linux】系統編程-7-網路編程
- 2021 年 1 月 20 日
- 筆記
- /label/linux, /label/linux/syspro, /label/lzm, C語言, linux, 嵌入式
目錄
前言
10. 網路編程
- 互聯網通訊所要遵守的眾多協議,被統稱為TCP/IP。
10.1 簡要網路知識
- TCP/IP是一個龐大的協議族,它是眾多網路協議的集合,包括:ARP、IP、ICMP、UDP、TCP、DNS、DHCP、HTTP、FTP、MQTT等等
- 分層
graph LR
A[應用層] –> a[DNS HTTP FTP SMTP MQTT郵件協議]
B[傳輸層] –> b[主要是TCP UDP]
C[網路層] –> c[主要為IP ICM ARP協議]
D[鏈路層] –> d[MAC層]
E[物理層] –> e[主要定義物理傳輸介質]
- 參考圖
10.2 IP協議
- IP協議(Internet Protocol),又稱之為網際協議,IP協議處於IP層工作,它是整個TCP/IP協議棧的核心協議
10.2.1 IP地址編址
- 參考圖
類別 | 第一位元組(二進位) | 第一位元組取值範圍 | 網路號個數 | 主機號個數 | 適用範圍 |
---|---|---|---|---|---|
A類 | 0XXX XXXX | 0-127 | 125 | 16777214 | 大型網路 |
B類 | 10XX XXXX | 128-191 | 16368 | 65534 | 中型網路 |
C類 | 110X XXXX | 192-223 | 209715 | 254 | 小型網路 |
D類 | 1110 XXXX | 224-239 | – | – | 多播 |
E類 | 1111 XXXX | 240-255 | – | – | 保留 |
10.2.2 特殊IP地址
10.2.1 首限廣播地址
- 受限廣播地址用於定義整個互聯網,如果設備想使IP數據報被整個網路所接收,就發送這個目的地址全為1的廣播包,但這樣會給整個互聯網帶來災難性的負擔,所以在任何情況下,路由器都會禁止轉發目的地址為255.255.255.255的廣播數據包,因此這樣的數據包僅會出現在本地網路中(區域網),255.255.255.255這個地址指本網段內的所有主機, 相當於「房子裡面的人都聽著」通知所有主機。
- 其實就是對整個IP生效,即網路號+主機號都全為1,對整個互聯網生效
10.2.2 直接廣播地址
- 直接廣播地址僅是主機號為1,廣播地址代表本網路內的所有主機。
- 其實就是對整個IP生效,即主機號都全為1,對同一網路號內的所有主機生效
10.2.3 多播地址
- 多播地址用在一對多的通訊中,屬於分類編址中的D類地址, D類地址只能用作目的地址,而不能作為主機中的源地址。
10.2.4 迴環地址
- 127網段的所有地址都稱為環回地址,主要用來測試網路協議是否工作正常的作用。比如在電腦中使用ping 命令去ping 127.1.1.1就可以測試本地TCP/IP協議是否正常。用通俗的話表示,就是「我自己」,不能以127網段中的IP地址作為主機地址,因此A類地址又少了一個可用網路號。
10.2.5 本網路本主機
- IP地址32bit全為0的地址(0.0.0.0)表示的是本網路本主機,這個IP地址在IP數據報中只能用作源IP地址,這發生在當設備啟動時但又不知道自己的IP地址情況下。
- 在使用DHCP分配IP地址的網路環境中,這樣的地址是很常見的,主機為了獲得一個可用的IP地址,就給DHCP伺服器發送IP數據報,並用這樣的地址(0.0.0.0)作為源地址,目的地址為255.255.255.255(因為主機這時還不知道DHCP伺服器的IP地址),然後DHCP伺服器就會知道這個主機暫時沒有IP地址,那麼就會分配一個IP給這個主機。
10.3 UDP協議
- UDP 是User Datagram Protocol的簡稱, 中文名是用戶數據報協議
- 特點
- 無連接,即通訊時不需要創建連接(發送數據結束時也沒有連接可以釋放)所以減小了開銷和發送數據前的時延;
- 不可靠,最大努力交付,不保證可靠交付,因此主機不需要維護複雜的連接狀態;
- 面向報文,只在應用層交下來的報文前增加了首部後就向下交付IP層;
- 無流量控制和無阻塞控制,即使網路中存在阻塞,也不會影響發送端的發送頻率;
- 支援一對一、一對多、多對一、多對多的交互通訊;
- 首部開銷小,只有8個位元組,它比TCP的20個位元組的首部要短;
- 速度快,UDP沒有TCP的握手、確認、窗口、重傳、擁塞控制等機制,UDP是一個無狀態的傳輸協議,所以它在傳遞數據時非常快,即使在網路擁塞的時候UDP也不會降低發送的數據。
- 應用環境
- 常用於實時影片的傳輸,比如直播、網路電話等,因為即使是出現了數據丟失的情況,導致影片卡幀,是可以容忍的
10.4 TCP協議
- TCP是提供一種面向連接、可靠的位元組流傳輸服務
- 與UDP的區別
- TCP面向連接、數據可靠。
- UDP運載的數據是以報文的形式,各個報文在網路中互不相干傳輸,到達目標主機的順序是不一樣的,所以需要在應用層進行重裝。
- TCP採用數據流的形式傳輸,TCP協議會給每個傳輸的位元組進行編號,在傳輸的過程中,發送方把數據的起始編號與長度放在TCP報文中,在接收方將所有數據按照編號組裝起來,然後返回一個確認,當所有數據接收完成後才將數據遞交到應用層中。
- TCP的特性
- 連接機制:TCP是一個面向連接的協議
- 確認與重傳:一個完整的TCP傳輸必須有數據的交互。發送方發送數據後必須等待接收方的結果回饋,並開啟定時器,超時未接收到數據則認為發送失敗,進行重發操作;接收方接收到數據後必須向發送方回饋結果。
- 緩衝機制:
- 發送方:應用程式的數據大小、類型都是不可預估的。在數據量很小時,TCP會將數據存儲在一個緩衝空間中,等到數據量足夠大的時候進行發送數據,直至確認接收方正確接收成功才刪除。
- 接收方:由於網路中傳輸的數據報到達接收方的時間是不一樣的,所以需要存起來進行重裝再交給應用層。
- 全雙工通訊:TCP是全雙工通訊。雙方都是主機,任意一方都可以斷開鏈接。
- 流量控制:
- 流量控制是一個速度匹配服務,即發送方的發送速率與接收方應用程式的讀取速率相匹配。
- TCP通過讓發送方維護一個稱為接收窗口(receive window)的變數來提供流量控制。
- 接收窗口(rwnd),接收方會將此窗口值放在 TCP 報文的首部中的窗口欄位,然後傳遞給發送方,這個窗口的大小是在發送數據的時候動態調整的。
- 若發送方收到的窗口值為0,此時發送方還是會進行發送只有一個位元組的報文段。
- 差錯控制:TCP協議採用校驗和的方式來檢驗數據有效性。同時,接收方也會把接收到的數據報進行整理,重裝。
- 擁塞控制:在網路中擁塞的情況下調整自身的發送速度,這種形式對發送方的控制被稱為擁塞控制(congestion control),採取的措施是限制發送方的發送速度。
10.5 埠號的概念
- TCP連接是兩個不同主機的應用連接,而傳輸層與上層協議是通過埠號進行識別的。
- 埠號的取值範圍為:0~65535,不同埠號對應上層應用的不同執行緒
- 一台主機可能只有一個IP地址,但是可以有多個埠號
- 通過 IP地址+埠號 來區分主機不同的執行緒。
- 常見的TCP協議埠號有21、53、80等等
埠號 | 協議 | 說明 |
---|---|---|
20/21 | FTP | 文件傳輸協議,使得主機間可以共享文件。 |
23 | Telnet | 終端遠程登錄,它為用戶提供了在本地電腦上完成遠程主機工作的能力。 |
25 | SMTP | 簡單郵件傳輸協議,它幫助每台電腦在發送或中轉信件時找到下一個目的地。 |
69 | TFTP | 普通文件傳輸協議。 |
80 | HTTP | 超文本傳輸協議,通過使用網頁瀏覽器、網路爬蟲或者其它的工具,客戶端發起一個HTTP請求到伺服器上指定埠(默認埠為80),應答的伺服器上存儲著一些資源,比如HTML文件和影像,那麼就會返回這些數據到客戶端。 |
110 | POP3 | 郵局協議版本3,本協議主要用於支援使用客戶端遠程管理在伺服器上的電子郵件。 |
10.6 TCP報文段
- TCP報文段由 首部 + 數據域 組成
10.7 TCP建立連接
- TCP是一個面向連接的協議,連接俗稱握手。
- 三次握手建立連接
- 建立連接的過程是由客戶端發起,服務端等待客戶請求
- 第一步:客戶端向伺服器端發送一個SYN報文段(只有首部,且SYN被置 1),初始序號(ISN)隨機選擇,假設為A,ACK置 0。
- 第二步:伺服器端收到SYN報文段,便知道客戶端需要請求握手,從SYN報文段中提取對應的資訊,為該TCP連接分配TCP快取和變數,並向該客戶TCP發送允許連接的報文段(握手應答報文)。這個報文段只有首部,包含3個重要的資訊:(建立客戶端–>服務端的連接)
- SYN與ACK標誌位1
- 將TCP報文段首部的確認序號欄位設置為A+1(這個A(ISN)是從握手請求報文中得到)。
- 伺服器隨機選擇自己的初始序號(ISN,注意此ISN是伺服器端的ISN,假設為B),並將其放置到TCP報文段首部的序號欄位中。
- 第三步:客戶端接收到伺服器端的握手應答後,會將SYN置 0,ACK置 1,確認序號置為 B+1, 設置窗口值,可以添加數據域的報文段發給伺服器端。同時給該TCP連接分配快取和變數。(建立服務端–>客戶端的連接)
- 參考圖:
10.8 TCP終止連接
- 建立連接需要三次握手,而終止連接需要四次揮手。
- 四次揮手終止連接
- 第一步:客戶端發出FIN報文段(首部FIN被置 1),序號假設為C,ACK被置 1,但是確認序號是無效的。
- 第二步:當伺服器端收到FIN報文段,它返回一個ACK報文段(終止連接應答),確認序號為C+1。此時斷開客戶端–>伺服器端的方向。
- 第三步:伺服器端發出FIN報文段向客戶端請求終止連接,此時序號為D,ACK被置 1,但是確認序號是無效的。
- 第四步:當客戶端收到FIN報文段,它返回一個ACK報文段(終止連接應答),確認序號為D+1。此時斷開伺服器端–>客戶端的連接。
- 參考圖
10.9 TCP狀態
- TCP協議的狀態如下:
- CLOSED:初始狀態,表示TCP連接是「關閉著的」或「未打開的」。
- LISTEN :表示伺服器端的某個SOCKET處於監聽狀態,可以接受客戶端的連接。
- SYN_RCVD :表示伺服器接收到了來自客戶端請求連接的SYN報文。在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態,很短暫,基本上用netstat很難看到這種狀態,除非故意寫一個監測程式,將三次TCP握手過程中最後一個ACK報文不予發送。當TCP連接處於此狀態時,再收到客戶端的ACK報文,它就會進入到ESTABLISHED狀態。
- SYN_SENT :這個狀態與SYN_RCVD狀態相呼應,當客戶端SOCKET執行connect()進行連接時,它首先發送SYN報文,然後隨即進入到SYN_SENT 狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。
- ESTABLISHED :表示TCP連接已經成功建立。
- 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()主動要求關閉連接。注意:FIN_WAIT_2是沒有超時的(不像TIME_WAIT狀態),這種狀態下如果對方不關閉(不配合完成4次揮手過程),那這個 FIN_WAIT_2 狀態將一直保持到系統重啟,越來越多的FIN_WAIT_2狀態會導致內核crash。
- TIME_WAIT :表示收到了對方的FIN報文,並發送出了ACK報文。 TIME_WAIT狀態下的TCP連接會等待2*MSL(Max Segment Lifetime,最大分段生存期,指一個TCP報文在Internet上的最長生存時間。每個具體的TCP協議實現都必須選擇一個確定的MSL值,RFC 1122建議是2分鐘,但BSD傳統實現採用了30秒,Linux可以在cat/proc/sys/net/ipv4/tcp_fin_timeout看到本機的這個值),然後即可回到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報文給對方,此時TCP連接則進入到CLOSE_WAIT狀態。接下來呢,你需要檢查自己是否還有數據要發送給對方,如果沒有的話,那你也就可以close()這個SOCKET並發送FIN報文給對方,即關閉自己到對方這個方向的連接。有數據的話則看程式的策略,繼續發送或丟棄。簡單地說,當你處於CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。
- LAST_ACK :當被動關閉的一方在發送FIN報文後,等待對方的ACK報文的時候,就處於LAST_ACK狀態。當收到對方的ACK報文後,也就可以進入到CLOSED可用狀態了。
參考
* 野火