計算機網絡的核心是連接與通信,從底層的物理信號到上層的應用服務,各層協議協同工作
---------------------------------------------------------------------------------------
一.計算機網絡分類(按范圍)
1?個人區域網(PAN)
通常是幾米到幾十米,用于連接個人設備,如手機、平板、手表等,包括藍牙Bluetooth、紫蜂Zigbee(低功耗設備)、紅外線IrDA(遙控器)
2?局域網(LAN)
通常覆蓋一個建筑物,用于小范圍內實現高速數據傳輸,包括以太網Ethernet(有線設備),Wi-Fi(無線設備)
3?城域網(MAN)
通常覆蓋一個城市,用于連接多個局域網,提供城域范圍內的數據傳輸服務,如光纖網絡
4?廣域網(WAN)
通常覆蓋一個國家,用于連接多個局域網和城域網,實現長距離數據傳輸,如互聯網Internet、企業專用網
---------------------------------------------------------------------------------------
二.計算機網絡分層模型
將復雜網絡通信劃分為若干層,每一層執行特定功能,并為上一層提供服務,兩層之間通過接口交互
1?OSI模型(國際標準模型)
物理層--數據鏈路層--網絡層--傳輸層--會話層--表示層--應用層
2?TCP / IP模型(實踐模型)
--鏈路層:包含物理層和數據鏈路層,涉及在物理網絡(通過有線與無線媒介)上的數據通信,還負責幀同步、錯誤檢測、校正等,包括以太網、Wi-Fi、PPP協議
--互聯網層:負責將數據報文段從原地址路由到目的地址,定義了在各種網絡結構中如何接發數據包,定義計算機設備地址,包括IP協議
--傳輸層:管理端到端的通信,負責為不同主機上的應用程序提供數據傳輸,定義設備應用地址(端口號),包括TCP、UDP協議
--應用層:使用下層提供的服務創建用戶數據,實現客戶的與服務端之間的通信,包括HTTP、SSH、MQTT協議
注意:后端編程是應用層中聚焦于服務器端邏輯實現的部分,前端編程是應用層直接面向用戶的界面與交互層,兩者協同完成整個應用的功能
3?數據傳輸單位
協議數據單元(PDU):包括頭部(PCI)和負載(SDU),是各層交換信息的數據單位,在網絡層稱為數據包、在傳輸層稱為報文段或數據報、在數據鏈路層稱為幀
負載(SDU):是通信協議的特定層次上傳遞的數據單元,數據傳遞到下一層會進行封裝,并附加控制信息PCI,轉換成PDU
頭部(PCI):是PDU的元數據部分,包括傳輸數據的控制信息,比如地址、端口號、控制標志、協議類型等,使得網絡或傳輸實體能理解如何處理SDU
4?IP協議(網絡層)
網絡通信最基礎的協議之一,分配IP地址給連接到計算機網絡的每個設備的唯一標識符
IPv4:從0.0.0.0到256.256.256.256
IPv6:為了解決IPv4地址數量不足問題,設計出IPv6
私有IP地址:僅在局域網中使用的IP地址,不能直接訪問互聯網,也無法被互聯網上的設備直接訪問
公有IP地址:由互聯網服務提供商分配,是設備在互聯網上的唯一標識
靜態IP地址:手動分配,不會改變,適用于需要長期保持相同IP的設備,如服務器
動態IP地址:由服務器動態分配,每次連接網絡時可能會改變,適用于普通用戶設備,如手機、電腦
路由器:工作在網絡層,用于連接不同的網絡,將數據包傳輸到目的地
5?DNS協議(應用層)
域名解析協議,用于將易讀的域名(www.com)轉換為計算機可以識別的IP地址
遞歸查詢:輸入域名-查詢本地緩存靜態文件-查詢本地DNS服務器--查詢根域名服務器--查詢頂級域名服務器(查詢不到該域名IP地址才會向上遞歸查詢)
6?數據鏈路層
在兩個網絡實體之間提供數據鏈路的連接,負責導線(無線或有線媒介)一端到一端的數據傳輸
MAC地址:是網絡設備的硬件地址,用在局域網(LAN)中唯一的設備ID
ARP協議:將IP地址轉換為物理MAC地址,用于局域網中已知目標設備IP地址,不知MAC地址時,獲得目標設備的MAC地址(通過IP地址廣播獲得)
7?物理層
負責傳輸數據的物理通道(模擬信號、物理信號),負責比特傳輸、物理連接、信號編碼和調制、數據速率控制、傳輸模式、物理拓撲
RS232協議與RS485協議:RS232常用于短距離點對點通信,如鼠標、鍵盤;RS485常用于長距離多點通信,如工業自動化系統
---------------------------------------------------------------------------------------
三?TCP協議
TCP:面向連接的協議,數據交換前,兩個通信段必須建立連接,包含可靠傳輸、流量控制、擁塞控制、數據排序、端到端通信
1?報文段格式
16 位源端口號--16位目的端口號:用于區分網絡服務,實現端到端通信
32位序列號:用于標識數據字節流,給每個字節分配標號,TCP能根據標號重新排序亂序到達的報文段,實現數據排序
32位確認序列號:用于接收到數據的確認,是發送方期望從對方收到的下一字節的標號,也是對之前收到的數據的確認,實現可靠傳輸
4位數據偏移:用于表示TCP頭部長度,除了固定20字節部分,還可以包含可變長度的選項字段,將首部與數據部分區分開來
6位保留位:還未確定功能,必須為0
6位控制位:URG(緊急標志)、ACK(確認標志)、PSH(立即上傳標志)、RST(鏈接錯誤標志)、SYN(建立連接標志)、FIN(斷開連接標志),控制不同行為
16位窗口大小位:用于控制對方發送的數據量,以避免接收區緩沖區溢出,實現流量控制
注意:TCP連接中,雙方各自維護一個緩沖區,為防止緩沖區溢出,使用滑動窗口機制控制發送方的發送速率,接收方會在返回的ACK報文段設置窗口大小位
16位TCP校驗和:用于檢查整個報文段的錯誤,實現可靠傳輸
16位緊急指針數據偏移量:當URG標志為1時,代表為緊急數據,表明從當前序列號開始的緊急數據的字節偏移量
選項區:可能包含的各種可選字段
填充區:TCP是在32位體系結構設計,為了內存對齊以提升效率,需要確保頭部長度為32位的整數倍
2?TCP狀態
-- CLOSED:初始狀態和最終狀態,表示沒有連接,也沒有正在進行通信
-- LISTEN:服務器端監聽來自客戶端的連接請求,等待SYN報文進入連接
-- SYN_SENT:客戶端發送SYN包連接請求到服務器端,轉入SYN_SENT狀態等待服務器確認
-- SYN_RECEIVED:服務器端接收到客戶端的SYN報文后,響應SYN+ACK報文,同時進入SYN_RECEIVED狀態,代表服務器端已同意連接請求
-- ESTABLISHED:服務器端和客戶端連接已建立,可以進行數據傳輸,三次握手成功后,雙方都會進入的狀態
注意:以上為TCP的連接建立過程,又稱為三次握手(客戶端發送SYN-服務端發送SYN和ACK-客戶端發送ACK)
-- FIN_WAIT_1:當一端已完成數據傳輸任務后,會發送FIN報文,表示已經完成數據發送,進入該狀態
-- CLOSE_WAIT:接收到對方發送的FIN報文后,進入該狀態,代表連接一方沒有數據發送,但是本端可能還有需要發送的數據
-- FIN_WAIT_2:在發送FIN報文后,且對方回應ACK響應后,進入該狀態,等待連接一方的FIN報文
-- TIME_WAIT:接收到對方的FIN報文并發送ACK響應后,進入該狀態,該狀態會持續一段時間,確保對方接收到最后一個ACK報文
注意:以上為TCP連接釋放過程,又稱為四次揮手(客戶端發送FIN-服務端發送ACK-服務端發送FIN和ACK-客戶端發送ACK)
3?擁塞控制
由于網絡或其他環境因素影響,導致網絡傳輸能力受限,發送方無法在超時前收到ACK,不斷重傳導致進一步加劇擁堵,所以設立擁塞窗口,由發送方維護
--慢啟動:每接收到一個ACK,擁塞窗口的初始大小翻倍,這一階段窗口大小呈指數增長
--擁塞避免:當擁塞窗口大小到達設立的慢啟動閾值,進入該階段,此階段每接收到一個ACK,窗口大小加1,此階段窗口大小呈線性增長
--超時重傳:當出現報文段的丟失,則將慢啟動閾值設為當前窗口大小的一半,然后將窗口大小設為初始值,重新開啟慢啟動階段
--快速重傳:累計確認的方式使得某個報文段發生丟失,即便收到了后面的數據也會回應相同的ACK,當連續接收到3個重復的ACK時,判定相應的報文段丟失,立即重傳
--快速恢復:當發生快速重傳后,將慢啟動閾值設為當前擁塞窗口大小一半,且擁塞窗口直接設置為閾值,不執行慢啟動
區別:接收窗口是接收方發送給發送方的ACK報文中設置可接收數據速度,擁塞窗口是發送方認為網絡可以承擔的發送數據速度,實際發送速率是他倆的最小值
注意:可使用可視化工具wireshark進行三次握手、數據傳輸、四次揮手的消息監測
4?TCP開發常用函數
套接字作為操作系統提供的網絡編程接口(API),其內部已經封裝了大量的底層網絡通信細節,讓開發者無需直接處理復雜的協議邏輯(可分層選擇協議)
套接字內部實現:TCP(連接、各種機制、釋放)、UDP、地址與端口管理、數據緩沖與I/O處理、連接狀態管理、錯誤處理與信號通知等
套接字組成:網絡地址(通常使用IP)、端口號(標識設備上的特定應用或進程)、協議(如TCP與UDP定義傳輸規則)
4?1 單連接服務端進程(使用IPv4為例)
--定義地址結構體:使用IPv4地址結構體的定義,struct ?sockaddr_in ?server_addr,client_addr,并使用memset(&addr,0,sizeof(addr)清空內容
--填寫結構體中服務端地址協議:server_addr.sin_family = AF_INET,由于定義的IPv4地址結構體,所以此處必須選用AF_INET表達使用IPv4協議地址
--填寫結構體中服務端IP地址:server_addr.sin_addr.s_addr = htonl(INADDR_ANY),讓服務器綁定本機的所有可用IP地址(宏定義)
注意:htonl表示字節轉換,網絡協議要求使用大端字節序,主機CPU可能使用小端字節序,需要將主機字節序轉換為網絡字節序(htonl、htons、ntohs、ntohl)
--填寫結構體服務端端口號:server_addr.sin_port = htons(1234),其中htons,h表示host,n表示net,s表示short,最終實現將端口號寫入地址結構體
--創建:socket(通信域,創建類型,補充協議),通信域常使用AF_INET,表示使用IPv4互聯網協議;創建類型常使用SOCK_STREAM或SOCK_DGRAM,表示使用TCP或UDP協議傳輸;補充協議涉及硬件補充設施,使用0會自動進行選擇補充協議;函數成功會返回int類型的文件描述符sockfd
--綁定地址:bind(sockfd,結構體地址指針sockaddr,結構體地址長度),將sockaddr指定的地址綁定文件描述符sockfd(此處使用&server_addr)
--服務端監聽:listen(sockfd,還未接收等待連接的隊列長度),將地址綁定后,可以直接進入監聽狀態
--獲取客戶端連接:accept(sockfd,接收的客戶端的地址,地址長度的指針),建立連接,可以接收到客戶端的地址(此處地址使用&client_addr),并返回int類型客戶端文件描述符clientfd,使用該文件描述符進行數據的傳輸,若沒有客戶端連接,則服務端將掛起等待
--創建發送消息進程與接收消息線程:使用pthread_create創建線程read_from_client、write_to_client,并將客戶端描述符clientfd傳入線程
--接收消息線程:malloc設置接收緩沖區,使用recv接收客戶端描述符的數據,即客戶端傳送的數據,若返回值為0則代表客戶端主動關閉連接,free釋放接收緩沖區
--發送消息線程:接收控制臺信息使用send發送數據給客戶端描述符
--收尾:使用pthread_join收尾子線程,使用close關閉服務端和客戶端文件描述符
4?2 單連接客戶端進程(使用IPv4為例)
--定義地址結構體:使用IPv4地址結構體的定義,struct ?sockaddr_in ?server_addr,client_addr,并使用memset(&addr,0,sizeof(addr)清空內容
--填寫結構體中客戶端地址協議:client_addr.sin_family = AF_INET
--填寫結構體中客戶端IP地址:inet_pton(AF_INET,“192.168.0.0”,&client_addr.sin_addr.s_addr),讓客戶端綁定特定IP地址
--填寫結構體客戶端端口號:client_addr.sin_port = htons(5678)
--填寫結構體中服務端地址協議:server_addr.sin_family = AF_INET
--填寫結構體中服務端IP地址:inet_pton(AF_INET,“0.0.0.0”,&server_addr.sin_addr.s_addr),使用時需寫上服務端的IP地址
--填寫結構體服務端端口號:server_addr.sin_port = htons(1234)
--創建:socket(通信域,創建類型,補充協議),通信域常使用AF_INET,表示使用IPv4互聯網協議;創建類型常使用SOCK_STREAM或SOCK_DGRAM,表示使用TCP或UDP協議傳輸;補充協議涉及硬件補充設施,使用0會自動進行選擇補充協議;函數成功會返回int類型的文件描述符sockfd
--綁定地址:bind(sockfd,結構體地址指針sockaddr,結構體地址長度),將sockaddr指定的地址綁定文件描述符sockfd(此處使用&client_addr)
--主動連接服務端:connect(sockfd,連接的服務端地址,地址長度的指針),前提需要服務端處于掛起狀態,返回值可以判斷是否連接成功(此處使用&server_addr)
--創建發送消息進程與接收消息線程:使用pthread_create創建線程read_from_server、write_to_server,并將客戶端描述符sockfd傳入線程
--接收消息線程:malloc設置接收緩沖區,使用recv接收客戶端描述符的數據,即服務端傳送的數據,若返回值為0則代表服務端主動關閉連接,free釋放接收緩沖區
--發送消息線程:接收控制臺信息使用send發送數據給客戶端描述符
--收尾:使用pthread_join收尾子線程,使用close關閉客戶端文件描述符
注意:TCP連接是全雙工屬性,套接字讀寫操作各自對應發送、接收緩沖區的機制,所以可以實現同時的雙向傳輸
4?3 多連接
服務端獲取多個客戶端連接:套入while(1)不斷accept客戶端,獲得clientfd并創建與其對接的線程或進程,進行收發客戶端信息
客戶端連接服務端:客戶端可以不綁定地址,直接由系統自動分配一個空閑的端口號給客戶端
---------------------------------------------------------------------------------------
四?UDP協議
UDP:面向無連接的協議,通信前不需要建立連接,直接發送數據報,傳輸效率高,適用于對實時性要求高但可容忍少量數據丟失的場景,如直播、游戲、視頻通話等
1?區別
相比TCP,UDP不存在握手與揮手,服務端不需要listen、accept,客戶端不需要connect,兩端都不能確定對方是否收到消息(發送方需要知道接收方地址)
2?UDP開發常用函數
2?1 服務端進程
--定義地址結構體--填寫結構體中服務端地址協議--填寫結構體中服務端IP地址--填寫結構體服務端端口號--創建socket--綁定地址bind
--接收數據:recvfrom(sockfd,buf,1024,0,&client_addr,地址長度),將客戶端發送的數據接收到buf中
--回復數據:sendto(sockfd,buf,4,0,&client_addr,地址長度),將buf內數據發送給客戶端
2?2?客戶端進程
--定義地址結構體--填寫結構體中服務端地址協議--填寫結構體中服務端IP地址--填寫結構體服務端端口號--創建socket(客戶端不需要綁定地址)
--接收數據:recvfrom(sockfd,buf,1024,0,&server_addr,地址長度),將服務端發送的數據接收到buf中
--發送數據:sendto(sockfd,buf,4,0,&server_addr,地址長度),將buf內數據發送給服務端
---------------------------------------------------------------------------------------
五.Socket IPC(進程通信)
專門處理同一臺機器上的進程間通信,屬于本地通信(不用走網卡)
1?定義結構體套接字
struct sockaddr_un socket_addr、client_addr;memset(&socket_addr,0,sizeof(socket_addr))
2?服務端流程
--創建套接字:socket(AF_UNIX,SOCK_STREAM,0),返回服務端描述符sockfd
--綁定路徑:socket_addr.sun_family =?AF_UNIX; strcpy(socket_addr.sun_path,unix_domain.socket),不同進程通過unix_domain.socket路徑找到套接字
--綁定本地地址:bind(sockfd,&socket_addr,sizeof(socket_addr)),使套接字與該路徑關聯
--監聽:listen(sockfd,5)
--接收:accept(sockfd,&client_addr,sizeof(client_addr)),返回客戶端描述符connfd
3?客戶端流程
--創建套接字:socket(AF_UNIX,SOCK_STREAM,0),返回客戶端描述符sockfd
--綁定路徑:client_addr.sun_family =?AF_UNIX; strcpy(client_addr.sun_path,unix_domain.socket),和服務器端綁定相同路徑才能找到
--連接:connect(sockfd,&client_addr,sizeof(client_addr))
4?收尾
--close(sockfd)、close(connfd)、服務器需要unlink(socket_addr.sun_path),避免下次綁定報錯
?