網絡:基礎概念
在計算機發展過程中,最開始每個計算機時相互獨立的,后來人們需要用計算機合作處理任務,這就牽扯到了數據交換,所以最開始的網絡就誕生了。一開始,網絡都是局域網LAN
,后來技術成熟,計算機設備增多,廣域網WAN
就來了。這里的局域網和廣域網都是一個相對的概念。
計算機作為人的工具,人要協同工作,者注定了網絡必然產生。一切都是最好的安排。
協議
協議就是通信雙方約定好的通信方式
一開始,計算機都是在局域網中進行數據通信,各個局域網都有自己的通信標準(協議)。后來一些比較權威的組織,開始制定詳盡的協議
國際標準化組織:
IEEE(電氣和電子工程師協會):這是一個由計算機和工程領域專家組成的龐大技術組織,在通信協議領域貢獻突出。
IEEE
制定了全世界電子、電氣和計算機科學領域 30%左右的標準,包括 IEEE 802 系列標準,這些標準涵蓋了從局域網(LAN)到廣域網(WAN)等多種網絡技術。ISO(國際標準化組織):
ISO
是由多個國家的標準化團體組成的國際組織,它在開放系統互連(OSI)模型方面的工作尤為著名。OSI
模型定義了網絡通信的七層協議結構,盡管在實際應用中,TCP/IP
協議族更為普遍,但OSI
模型仍然在學術和理論研究中占有重要地位。ITU(國際電信聯盟):
ITU
是聯合國下屬的專門機構,負責制定電信領域的國際標準。ITU-T
制定的標準涵蓋了電話和網絡通信,與ISO
合作確保了通信技術的全球兼容性和互操作性。區域標準化組織:
ETSI(歐洲電信標準學會):由歐洲共同體各國政府資助,是一個由電信行業的廠商與研究機構參加并從事研究開發到標準制定的組織。
ASTAP(亞洲與泛太平洋電信標準化協會):1998 年由日本與韓國發起成立的標準化組織,旨在加強亞洲與太平洋地區各國信息通信基礎設施及其相互連接的標準化工作的協作。
公司:某些公司,如泰凌微,也自研各種標準的軟件協議棧,包括低功耗藍牙、
zigbee
、thread
及Matter
等,并可進行定制化改動,這是其核心競爭力之一。泰凌微還計劃重點發展智能電子價簽、智能遙控、智能家居等市場。民間國際團體:
IETF(互聯網工程師任務組):這是一個負責開發和推廣互聯網協議(特別是構成
TCP/IP
協議族的協議)的志愿組織,通過 RFC 發布新的或者取代老的協議標準官方機構:
FCC(聯邦通信委員會):美國對通信技術的管理的官方機構,主要職責是通過對無線電、電視和有線通信的管理來保護公眾利益。也對包括標準化在內的通信產品技術特性進行審查和監督。
OSI七層網絡協議模型
軟件分層是為了更好的解耦,降低維護成本
OSI(
Open System Interconnection
,開放系統互連)七層網絡模型稱為開放式系統互聯參考模型,是一個邏輯上的定義和規范; 把網絡從邏輯上分為了 7 層. 每一層都有相關、相對應的物理設備,比如路由器,交換機OSI 七層模型是一種框架性的設計方法,其最主要的功能使就是幫助不同類型的主機實現數據傳輸
它的最大優點是將服務、接口和協議這三個概念明確地區分開來,概念清楚,理論也比較完整. 通過七個層次化的結構模型使不同的系統不同的網絡之間實現可靠的通訊
為了降低學習成本,我們將它簡化,按照
TCP/IP
四層模型來講解
在網絡角度,OSI
定制的七層模型非常完善,但是在實操過程中,會話層,表示層是不可能接入到OS
中的,所以在工程實踐中,在最終落地的是五層協議,數據鏈路層下面還有一個物理層
物理層: 負責光/電信號的傳遞方式. 比如現在以太網通用的網線(雙絞線)、早期以太網采用的的同軸電纜(現在主要用于有線電視)、光纖, 現在的
wifi
無線網使用電磁波等都屬于物理層的概念。物理層的能力決定了最大傳輸速率、傳輸距離、抗干擾性等。集線器(Hub)工作在物理層。數據鏈路層: 負責設備之間的數據幀的傳送和識別。例如網卡設備的驅動、幀同步(就是說從網線上檢測到什么信號算作新幀的開始)、沖突檢測(如果檢測到沖突就自動重發)、數據差錯校驗等工作。有以太網、令牌環網,無線
LAN
等標準. 交換機(Switch)工作在數據鏈路層。網絡層: 負責地址管理和路由選擇。例如在
IP
協議中,通過IP
地址來標識一臺主機, 并通過路由表的方式規劃出兩臺主機之間的數據傳輸的線路(路由)。路由器(Router)工作在網路層。傳輸層: 負責兩臺主機之間的數據傳輸。如傳輸控制協議 (TCP), 能夠確保數據可靠的從源主機發送到目標主機。
應用層: 負責應用程序間溝通,如簡單電子郵件傳輸(SMTP)、文件傳輸協議(FTP)、網絡遠程訪問協議(Telnet)等。我們的網絡編程主要就是針對應用層。
設備 | 實現的網絡層次(OSI 模型) | 核心功能舉例 |
---|---|---|
主機(內核) | 傳輸層、網絡層、數據鏈路層(軟件) | TCP 通信、IP 路由、Ethernet 幀處理 |
路由器 | 網絡層、數據鏈路層、物理層 | IP 轉發、跨網絡互聯 |
交換機 | 數據鏈路層、物理層 | MAC 地址轉發、局域網內通信 |
集線器 | 物理層 | 電信號放大與廣播 |
協議的本質
協議就是雙方的一種規定,就像摩斯密碼就是一種協議,通過規定某些行為來通過這些行為來傳遞信息。在語言層面,由于從傳輸層到網卡驅動層都是嵌入在操作系統中的。而操作系統又是C/C++
寫的,所以協議的本質就是通信雙方都認識的結構化的數據類型。
協議是分層的,所以網絡中的每層都有協議,同層之間,互相都有可以認識對方的協議。
網絡傳輸基本流程
局域網傳輸流程
兩臺主機在同一個局域網內是能夠直接通信的,每臺主機在局域網中都有一個標識來保證主機的唯一性:mac
地址(這貨實際上也是全球唯一,但由于歷史原因,mac
地址是在ip
地址后面發明的)
MAC地址
MAC
地址用來識別數據鏈路層中相連的節點長度位48位,及6個字節,一般用16進制數字加上冒號的形式來表示
08:00:27:03:fb:19
MAC
地址在網卡出廠時就確定了,不能修改,MAC
地址通常是唯一的(虛擬機中的MAC
地址不是真實的MAC
地址,可能會沖突;也有些網卡支持用戶配置MAC
地址)
以太網中,任何時刻,只允許一臺主機向網絡中發送數據,如果有多臺同時發送,會發生數據干擾,稱之為數據碰撞。所有發送數據的主機要進行碰撞檢測和碰撞避免。在沒有交換機的情況下,一個局域網就是一個碰撞域(所以現在你知道同一個局域網下設備多了網卡的原因了嗎?)局域網通信中主機對收到的報文確認是否是發給自己的,是通過目標MAC
地址來判定的
- 首先,我們要明確
報文 = 有效載荷 + 報頭
。然后,我們在明確一下不同層的完整報文的叫法 - 不同的協議層對數據包有不同的稱謂,在傳輸層叫做段
segment
,在網絡層叫做數據報datagram
,在鏈路層叫做幀frame
- 應用層數據通過協議棧發到網絡上時,每層協議都要加上一個數據首部
header
,稱為封裝Encapsulation
- 首部信息中包含了一些類似于首部有多長, 載荷
payload
有多長,上層協議是什么等信息 - 數據封裝成幀后發到傳輸介質上,到達目的主機后每層協議再剝掉相應的首部,根據首部中的“上層協議字段”將數據交給對應的上層協議處理
在網絡通信過程中,數據不是直接發送給對方主機的,而是先要自頂向下將數據交付給下層協議,最后由底層發送,然后由對方主機的底層接收,再自底向上交付
要學習一種協議,就是學習這個協議是工作在那一層的,它是如何封包,如何解包,如何分用,還有它是如何將自己的有效載荷交付給上層協議的
跨網絡傳輸流程
IP地址
IP
協議有兩個版本,IPV4
和IPV6
,后者目前應用不多(中國在IPV6
技術上是Top
)所以我們先學前者
- IP地址是在IP協議中,用來標識網絡中不同主機的地址
- 對于IPV4來說,IP地址是一個4字節,32位的整數
- 我們通常也使用“點分十進制”的字符串表示 IP 地址,例如
192.168.0.1
用點分割的每一個數字表示一個字節,范圍是 0 - 255
跨網段的主機數據傳輸,數據從一臺計算機到另外一臺計算機傳輸過程中要經過一個或多個路由器
因為目標主機和本主機不在同一個子網(局域網),而路由器又有構建子網的能力,所以一個路由器一般都有兩套網卡,兩個IP地址,用于構建兩個子網。所以當當前主機和目標主機不在同一個子網下時,數據要去到目標主機就要先去路由器,經過路由轉發到目標主機的子網,再將數據交給目標主機。
IP
地址在整個路由過程中,一直不變 TODOMac
地址一直在變- 目的
IP
是一種長遠目標,MAC
是下一階段目標,目的IP是路徑選擇的重要依據,MAC
地址是局域網轉發的重要依據 - 目的
IP
就是告訴你我的終點要去哪,MAC
地址就是告訴你,我下一站要去哪 IP
網絡層存在的意義:提供網絡虛擬層,讓世界的所有網絡都是IP
網絡,屏蔽最底層網絡的差異
MAC地址和IP地址
既然有了IP地址,為什么還需要MAC地址?
1、對于網絡中的一些設備,路由器或者是PC及而言,IP地址的設計是出于拓撲設計出來的,只要在不重復IP地址的情況下,它是可以隨意更改的;而MAC地址是根據生產廠商燒錄好的,它一般不能改動的,一般來說,當一臺PC機的網卡壞了之后,更換了網卡之后MAC地址就會變了。
2、在前面的介紹里面,它們最明顯的區別就是長度不同,IP地址的長度為32位,而MAC地址為48位。
3、它們的尋址協議層不同。IP地址應用于OSI模型的網絡層,而MAC地址應用在OSI模型的數據鏈路層。 數據鏈路層協議可以使數據從一個節點傳遞到相同鏈路的另一個節點上(通過MAC地址),而網絡層協議使數據可以從一個網絡傳遞到另一個網絡上(ARP根據目的IP地址,找到中間節點的MAC地址,通過中間節點傳送,從而最終到達目的網絡)。
4、分配依據不同。IP地址的分配是基于我們自身定義的網絡拓撲,MAC地址的分配是基于制造商。一個是主觀的,而另一種是可觀的。
5、最重要的區別在于,IP地址劃分時基于地理區域,換了不同地方,即便是同一臺硬件設備,IP地址一定不一樣,可以理解為和地理位置有關;而MAC地址不依賴于地理區域,換了不同地方,只要還是同一臺硬件設備,MAC地址就不會變,它只和硬件設備有關。
Socket編程
數據交給主機還不是網絡通信的最終目的,讓進程拿到數據,才是最終目的,我們啟動的上層應用,實際上都是進程,進程拿到了數據,也就相當于人拿到了數據。
因為一個主機中會有很多個進程,所以我們需要一個東西來標識進程在系統中的唯一性
端口號
- 端口號是一個2字節,16位的整數
- 端口號用來標識一個進程,告訴
OS
,當前的數據要交給哪一個進程處理 - 所以
IP地址 + 端口號
基本就能標識網絡中的某一臺主機上的某一個進程 - 一個端口只能被一個進程占用,但是一個進程可以綁定多個端口
端口劃分:
- 0 -1023: 知名端口號
HTTP
,FTP
,SSH
等這些廣為使用的應用層協議,他們的端口號都是固定的 - 1024 - 65535:操作系統動態分配的端口,客戶端程序的端口就是由OS從這個范圍分配的
有一個問題,為什么不在網絡上直接用pid
來標識進程的唯一性呢?
因為設計者不想讓系統和網絡強耦合,就像你已經有了能在社會上唯一標識的身份證,學校還是要給你分配一個學號
理解Socket
- 綜上,
IP
地址用來標識互聯網中唯一的一臺主機,port
用來標識該主機上唯一的一個網絡進程 IP+Port
就能表示互聯網中唯一的一個進程- 所以,通信的時候,本質是兩個互聯網進程代表人來進行通信,
{srcIp,srcPort,dstIp,dstPort}
這樣的 4 元組就能標識互聯網中唯二的兩個進程 - 所以,網絡通信的本質,也是進程間通信
- 我們把
ip + port
叫做套接字socket
認識傳輸層協議
TCP:傳輸層協議,有連接,可靠傳輸,面向字節流
UDP:傳輸層協議,無連接,不可靠傳輸,面向數據報
網絡字節序
我們已經知道,內存中的多字節數據相對于內存地址有大端和小端之分,磁盤文件中的多字節數據相對于文件中的偏移地址也有大端小端之分,網絡數據流同樣有大端小端之分。那么如何定義網絡數據流的地址呢?
- 發送主機通常將發送緩沖區中的數據按內存地址從低到高的順序發出;
- 接收主機把從網絡上接到的字節依次保存在接收緩沖區中,也是按內存地址從低到高的順序保存;
- 因此,網絡數據流的地址應這樣規定:先發出的數據是低地址,后發出的數據是高地址.
TCP/IP
協議規定,網絡數據流應采用大端字節序,即低地址高字節.- 不管這臺主機是大端機還是小端機,都會按照這個
TCP/IP
規定的網絡字節序來發送/接收數據; - 如果當前發送主機是小端,就需要先將數據轉成大端; 否則就忽略,直接發送即可;
CSDN有關整數和浮點數在內存中存儲
為使網絡程序具有可移植性,使同樣的 C 代碼在大端和小端計算機上編譯后都能正常運行,可以調用以下庫函數做網絡字節序和主機字節序的轉換。
- 這些函數名很好記,h表示
host
,n 表示network
,l 表示 32 位長整數,s 表示 16 位短整數 - 例如
htonl
表示將 32 位的長整數從主機字節序轉換為網絡字節序,例如將IP
地址轉換后準備發送 - 如果主機是小端字節序,這些函數將參數做相應的大小端轉換然后返回
- 如果主機是大端字節序,這些函數不做轉換,將參數原封不動地返回
Socket編程接口
// 創建 socket 文件描述符 (TCP/UDP, 客戶端 + 服務器)
int socket(int domain, int type, int protocol);
// 綁定端口號 (TCP/UDP, 服務器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
// 開始監聽 socket (TCP, 服務器)
int listen(int socket, int backlog);
// 接收請求 (TCP, 服務器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);
// 建立連接 (TCP, 客戶端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
sockaddr 結構
socket API
是一層抽象的網絡編程接口,適用于各種底層網絡協議,如 IPv4
、IPv6
、以及UNIX Domain Socket
然而,各種網絡協議的地址格式并不相同
IPv4
和IPv6
的地址格式定義在netinet/in.h
中,IPv4
地址用sockaddr_in
結構體表示,包括 16 位地址類型, 16 位端口號和 32 位 IP 地址IPv4
、IPv6
地址類型分別定義為常數AF_INET
、AF_INET6
. 這樣,只要取得某種sockaddr
結構體的首地址,不需要知道具體是哪種類型的sockaddr
結構體,就可以根據地址類型字段確定結構體中的內容socket API
可以都用struct sockaddr *
類型表示, 在使用的時候需要強制轉化成sockaddr_in
,這樣的好處是程序的通用性, 可以接收IPv4
,IPv6
,以及UNIX Domain Socket
各種類型的sockaddr
結構體指針做為參數
// Linux 2.6.18 內核typedef unsigned short sa_family_t;
struct sockaddr {sa_family_t sa_family; /* address family, AF_xxx */char sa_data[14]; /* 14 bytes of protocol address */
};/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {sa_family_t sin_family; /* Address family */unsigned short int sin_port; /* Port number */struct in_addr sin_addr; /* Internet address *//* Pad to size of `struct sockaddr'. */unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
};// 雖然 socket api 的接口是 sockaddr, 但是我們真正在基于 IPv4 編程時,
// 使用的數據結構是 sockaddr_in; 這個結構里主要有三部分信息: 地址類型,端口號,IP地址/* Internet address. */
struct in_addr {__u32 s_addr;
};
// in_addr 用來表示一個 IPv4 的 IP 地址. 其實就是一個 32 位的整數;