網絡協議棧是操作系統根據網絡模型的具體實現。
用戶層可以藉助於操作系統提供的功能進行與其他的主機進行網絡通信
交互主要分爲以下幾個步驟:
1 創建套接字
什麼是套接字
套接字指的實體是通信控制信息,控制信息裏面包含了通信對象的IP地址,端口號和通信操作進行狀態。
在linux中,套接字的實體所指的是套接字緩衝區域。
一個套接字緩衝區代表了一個網絡封包,套接字緩衝區可以代表不同的網絡封包。
linux裏面執行如下命令可以看到有多少個套接字:
netstat
上面就是所有的套接字以及它所包含的信息。
創建套接字指的是在內存中開闢一個存儲空間,並向這個空間內寫入初始化的信息。
如下所示就是python 創建socket的代碼,可以看到在進行初始化的時候,傳入了
綁定地址和端口信息。這些都會存儲到控制信息中(linux中對應套接字緩衝區)。
另外可以看到每一個套接字包含了不同的狀態。
import socket
sk = socket.socket()
sk.bind(("127.0.0.1",8080))
sk.listen(5)
conn,address = sk.accept()
sk.sendall(bytes("Hello world",encoding="utf-8"))
2 連接服務器
所謂的連接就是客戶端和服務器端交換控制信息。
負責保存控制信息的頭部
有些控制信息在通信的整個過程中都是需要的,這些控制信息需要保存在所發送的包的內部。
這些信息被稱爲“頭部”,不同的協議和網絡層在處理包的過程中都會加上自己的頭部。
爲了便於區分這些頭部被稱爲“TCP 頭部”, 以太網頭部和IP頭部。
在連接和斷開階段由於沒有對應的實際數據,所以傳遞的僅僅是網絡包。
連接操作的整個過程。
tcp的三次握手
tcp首先發起請求,將syn設置爲1
添加tcp頭部,並交給ip模塊傳遞包。
服務器接收到請求之後,找到對應的套接字,並返回消息。返回的時候syn要設置爲1,ack也要設置爲1
如果因爲某些原因無法連接時,則將rst字段設置爲1。
客戶端收到之後要返回一個數據包,並將ACK設置爲1,這樣整個連接也就建立了。
3 傳輸數據
連接建立之後,客戶端就可以調用write()函數進行數據的傳輸。
對於較小的數據片,協議棧會等到數據填滿後打包發送,這個數據的容量就是mtu值。
如果應用程序發送的數據包較小,那麼會影響發送的效率,協議棧會等到數據達到mtu值之後纔會發送。
當然這個是由程序來控制的。可以選擇不緩存而立馬發送,但是這樣會造成網絡的擁擠。
如果數據包過大,超過了mtu值那麼就需要對網絡包進行拆分。分成一個個的小包發送出去。
這樣網絡包就發送出去了,但是tcp是一個安全可靠的傳輸協議,必須保證包能夠抵達服務端。
這樣就需要一定的機制來保證。
-
使用ack確認網絡包已經收到
根據包的平均往返時間來調整ACK號的等待時間。
滑動窗口機制的原理,ACK值在返回的過程中可能會造成延遲,如果延遲過高,那麼
必然會造成重傳,如果重傳勢必會造成網絡更加擁擠。但是如果設置等待網絡ACK 包
的時間過長也會導致網絡速度變慢,因此需要爲延遲設置一個合適的時間。
4 斷開連接
5 IP與以太網的包收發操作
包結構
網卡是物理層設備,負責將電信號轉化爲數字信號。虛擬網卡尤其是linux的tap設備
是對網卡的模擬,它並不負責將電信號轉化爲數字信號,而是一個軟件,負責數字信號
的傳輸。
TCP協議的目的是保證數據的安全和可靠傳輸,所以它有三次握手和三次揮手的功能。
這整個算是傳輸層的能力。UDP也一樣,不過它不具備可靠傳輸的能力。
內核協議棧的IP模塊的主要功能是對包進行封裝傳輸。它並不關心TCP做了哪些事情。
舉個例子來說,我們在郵局寄東西的時候,汽車的運輸人員,他們不關心運輸的東西
是什麼,每一個物品都封裝成了一個個的包裹,包裹上面有面單,上面包含了發送地址和寄出地址。
IP模塊在接收到包之後會做兩件事情,添加IP頭部和MAC頭部。
MAC頭部在IP頭部的前面,由於在處理的時候先處理二層的MAC頭部,再
處理三層的IP頭部。
網卡有對應的網卡驅動程序,網卡的內部結構如下圖所示。它的主要功能是
將數字信號轉換爲電信號並傳輸出去。
參考文獻:計算機網絡是怎麼連接的