平面設(shè)計可以做網(wǎng)站?深圳互聯(lián)網(wǎng)公司50強
目錄
1. 理解源 IP 地址和目的 IP 地址
2.端口號?
2.1端口號(port)是傳輸層協(xié)議的內(nèi)容
2.2端口號范圍劃分
2.3理解 "端口號" 和 "進程 ID"
2.4理解 socket
?3.傳輸層的典型代表
3.1認(rèn)識 TCP 協(xié)議
3.2認(rèn)識 UDP 協(xié)議
4. 網(wǎng)絡(luò)字節(jié)序
?5. socket 編程接口
1. 理解源 IP 地址和目的 IP 地址
IP 在網(wǎng)絡(luò)中, 用來標(biāo)識主機的唯一性
? 注意: 后面我們會講 IP 的分類, 后面會詳細闡述 IP 的特點
但是這里要思考一個問題: 數(shù)據(jù)傳輸?shù)街鳈C是目的嗎? 不是的。 因為數(shù)據(jù)是給人用
的。 比如: 聊天是人在聊天, 下載是人在下載, 瀏覽網(wǎng)頁是人在瀏覽?
但是人是怎么看到聊天信息的呢? 怎么執(zhí)行下載任務(wù)呢? 怎么瀏覽網(wǎng)頁信息呢? 通過
啟動的 qq, 迅雷, 瀏覽器。
而啟動的 qq, 迅雷, 瀏覽器都是進程。 換句話說, 進程是人在系統(tǒng)中的代表, 只要把
數(shù)據(jù)給進程, 人就相當(dāng)于就拿到了數(shù)據(jù)。
所以: 數(shù)據(jù)傳輸?shù)街鳈C不是目的, 而是手段。 到達主機內(nèi)部, 在交給主機內(nèi)的進程,
才是目的。
但是系統(tǒng)中, 同時會存在非常多的進程, 當(dāng)數(shù)據(jù)到達目標(biāo)主機之后, 怎么轉(zhuǎn)發(fā)給目標(biāo)
進程? 這就要在網(wǎng)絡(luò)的背景下, 在系統(tǒng)中, 標(biāo)識主機的唯一性。
2.端口號?
2.1端口號(port)是傳輸層協(xié)議的內(nèi)容
- 端口號是一個 2 字節(jié) 16 位的整數(shù);
- 端口號用來標(biāo)識一個進程, 告訴操作系統(tǒng), 當(dāng)前的這個數(shù)據(jù)要交給哪一個進程來處理;
- IP 地址 + 端口號能夠標(biāo)識網(wǎng)絡(luò)上的某一臺主機的某一個進程;(互聯(lián)網(wǎng)中獨一無二的一個進程),網(wǎng)絡(luò)通信的本質(zhì)就是進程間通信,只是需要跨網(wǎng)絡(luò)。(進程間通信要滿足的條件:1.兩個進程具有獨立性(絕對的滿足) 2.兩個進程間要看到一個公共資源:網(wǎng)絡(luò)),因此我們基于? ?IP+PORT 的通信 稱之為Socket通信
- 一個端口號只能被一個進程占用.且一個進程可以綁定多個端口號; 但是一個端口號不能被多個進程綁定。
2.2端口號范圍劃分
0 - 1023: 知名端口號, HTTP, FTP, SSH 等這些廣為使用的應(yīng)用層協(xié)議, 他們的
端口號都是固定的.
1024 - 65535: 操作系統(tǒng)動態(tài)分配的端口號. 客戶端程序的端口號, 就是由操作
系統(tǒng)從這個范圍分配的.
2.3理解 "端口號" 和 "進程 ID"
????????我們之前在學(xué)習(xí)系統(tǒng)編程的時候, 學(xué)習(xí)了 pid 表示唯一一個進程; 此處我們的端口號也
是唯一表示一個進程. 那么這兩者之間是怎樣的關(guān)系?
????????進程 ID 屬于系統(tǒng)概念, 技術(shù)上也具有唯一性, 確實可以用來標(biāo)識唯一的一個進
程, 但是這樣做, 會讓系統(tǒng)進程管理和網(wǎng)絡(luò)強耦合(pid每次啟動的時候都會發(fā)送變化,那么兩者之間有聯(lián)系,意味著網(wǎng)絡(luò)部分也要發(fā)送變化), 實際設(shè)計的時候, 并沒有選擇這
樣做。我們要實現(xiàn)解耦,系統(tǒng)就是系統(tǒng),網(wǎng)絡(luò)就是網(wǎng)絡(luò),所以引入了端口號。? ? ? ? 但在系統(tǒng)中不是所有進程都有端口號,所有進程都有pid,只有需要進行網(wǎng)絡(luò)通信的進程才有端口號。
理解源端口號和目的端口號
????????傳輸層協(xié)議(TCP 和 UDP)的數(shù)據(jù)段中有兩個端口號, 分別叫做源端口號和目的端口號.
就是在描述 "數(shù)據(jù)是誰發(fā)的, 要發(fā)給誰"
2.4理解 socket
- 綜上, IP 地址用來標(biāo)識互聯(lián)網(wǎng)中唯一的一臺主機, port 用來標(biāo)識該主機上唯一的一個網(wǎng)絡(luò)進程
- ?IP+Port 就能表示互聯(lián)網(wǎng)中唯一的一個進程
- 所以, 通信的時候, 本質(zhì)是兩個互聯(lián)網(wǎng)進程代表人來進行通信, {srcIp,srcPort, dstIp, dstPort}這樣的 4 元組就能標(biāo)識互聯(lián)網(wǎng)中唯二的兩個進程
- ?所以, 網(wǎng)絡(luò)通信的本質(zhì), 也是進程間通信
- 我們把 ip+port 叫做套接字 socket
?3.傳輸層的典型代表
????????如果我們了解了系統(tǒng), 也了解了網(wǎng)絡(luò)協(xié)議棧, 我們就會清楚, 傳輸層是屬于內(nèi)核
的, 那么我們要通過網(wǎng)絡(luò)協(xié)議棧進行通信, 必定調(diào)用的是傳輸層提供的系統(tǒng)調(diào)用, 來
進行的網(wǎng)絡(luò)通信
3.1認(rèn)識 TCP 協(xié)議
此處我們先對 TCP(Transmission Control Protocol 傳輸控制協(xié)議)有一個直觀的認(rèn)識;
后面我們再詳細討論 TCP 的一些細節(jié)問題.
? 傳輸層協(xié)議
? 有連接
? 可靠傳輸(可靠性高)
? 面向字節(jié)流
3.2認(rèn)識 UDP 協(xié)議
此處我們也是對 UDP(User Datagram Protocol 用戶數(shù)據(jù)報協(xié)議)有一個直觀的認(rèn)識; 后
面再詳細討論.
? 傳輸層協(xié)議
? 無連接
? 不可靠傳輸(但操作簡單)
? 面向數(shù)據(jù)報
?
4. 網(wǎng)絡(luò)字節(jié)序
????????我們已經(jīng)知道,內(nèi)存中的多字節(jié)數(shù)據(jù)相對于內(nèi)存地址有大端和小端之分, 磁盤文件中的
多字節(jié)數(shù)據(jù)相對于文件中的偏移地址也有大端小端之分, 網(wǎng)絡(luò)數(shù)據(jù)流同樣有大端小端之
分. 那么如何定義網(wǎng)絡(luò)數(shù)據(jù)流的地址呢?
- ?發(fā)送主機通常將發(fā)送緩沖區(qū)中的數(shù)據(jù)按內(nèi)存地址從低到高的順序發(fā)出;
- ?接收主機把從網(wǎng)絡(luò)上接到的字節(jié)依次保存在接收緩沖區(qū)中,也是按內(nèi)存地址從低到高的順序保存;
- ?因此,網(wǎng)絡(luò)數(shù)據(jù)流的地址應(yīng)這樣規(guī)定:先發(fā)出的數(shù)據(jù)是低地址,后發(fā)出的數(shù)據(jù)是高地址.
- TCP/IP 協(xié)議規(guī)定,網(wǎng)絡(luò)數(shù)據(jù)流應(yīng)采用大端字節(jié)序,即低地址高字節(jié).
- 不管這臺主機是大端機還是小端機, 都會按照這個 TCP/IP 規(guī)定的網(wǎng)絡(luò)字節(jié)序來發(fā)送/接收數(shù)據(jù);
- 如果當(dāng)前發(fā)送主機是小端, 就需要先將數(shù)據(jù)轉(zhuǎn)成大端; 否則就忽略, 直接發(fā)送即可;
????????但后面是有了規(guī)定:網(wǎng)絡(luò)中通信,必須大端!?為使網(wǎng)絡(luò)程序具有可移植性,使同樣的 C 代碼在大端和小端計算機上編譯后都能正常運
行,可以調(diào)用以下庫函數(shù)做網(wǎng)絡(luò)字節(jié)序和主機字節(jié)序的轉(zhuǎn)換。
? 這些函數(shù)名很好記,h 表示 host,n 表示 network,l 表示 32 位長整數(shù),s 表示 16 位短整數(shù)。
? 例如 htonl 表示將 32 位的長整數(shù)從主機字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序,例如將 IP 地址轉(zhuǎn)換后準(zhǔn)備發(fā)送。
? 如果主機是小端字節(jié)序,這些函數(shù)將參數(shù)做相應(yīng)的大小端轉(zhuǎn)換然后返回;
? 如果主機是大端字節(jié)序,這些函數(shù)不做轉(zhuǎn)換,將參數(shù)原封不動地返回。
?
?5. socket 編程接口
socket 常見 API
?C / / 創(chuàng)建 socket 文件描述符 (TCP/UDP, 客戶端 + 服務(wù)器) int socket(int domain, int type, int protocol); // 綁定端口號 (TCP/UDP, 服務(wù)器) int bind(int socket, const struct sockaddr *address,socklen_t address_len); // 開始監(jiān)聽 socket (TCP, 服務(wù)器) int listen(int socket, int backlog); // 接收請求 (TCP, 服務(wù)器) int accept(int socket, struct sockaddr* address,socklen_t* address_len); // 建立連接 (TCP, 客戶端) int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockaddr 結(jié)構(gòu)
????????socket API 是一層抽象的網(wǎng)絡(luò)編程接口,適用于各種底層網(wǎng)絡(luò)協(xié)議,如 IPv4、 IPv6,以及
后面要使用的 UNIX Domain Socket. 然而, 各種網(wǎng)絡(luò)協(xié)議的地址格式并不相同。
? IPv4 和 IPv6 的地址格式定義在 netinet/in.h 中,IPv4 地址用 sockaddr_in 結(jié)構(gòu)
體表示,包括 16 位地址類型, 16 位端口號和 32 位 IP 地址.
? IPv4、 IPv6 地址類型分別定義為常數(shù) AF_INET、 AF_INET6. 這樣,只要取得某
種 sockaddr 結(jié)構(gòu)體的首地址,不需要知道具體是哪種類型的 sockaddr 結(jié)構(gòu)體,就可
以根據(jù)地址類型字段確定結(jié)構(gòu)體中的內(nèi)容.
? socket API 可以都用 struct sockaddr *類型表示, 在使用的時候需要強制轉(zhuǎn)化成
sockaddr_in; 這樣的好處是程序的通用性, 可以接收 IPv4, IPv6, 以及 UNIX Domain
Socket 各種類型的 sockaddr 結(jié)構(gòu)體指針做為參數(shù);(這就是C語言版本的多態(tài),頭部結(jié)構(gòu)一致,因此可以接收不同的結(jié)構(gòu)體)
sockaddr 結(jié)構(gòu)sockaddr_in 結(jié)構(gòu)
雖然 socket api 的接口是 sockaddr, 但是我們真正在基于 IPv4 編程時, 使用的數(shù)據(jù)結(jié)
構(gòu)是 sockaddr_in; 這個結(jié)構(gòu)里主要有三部分信息: 地址類型, 端口號, IP 地址
in_addr 結(jié)構(gòu)in_addr 用來表示一個 IPv4 的 IP 地址. 其實就是一個 32 位的整數(shù);
?