Linux 下互聯網絡編程的基礎知識_組播

TCP/IP 協議裏有兩種不同的協議:

1、TCP協議

用於檢測網絡傳輸中的差錯。

2、IP協議

用於對不同網絡進行互聯。

簡單説就是 TCP 負責糾錯,IP 負責傳輸。

 

網絡體系結構:

網絡體系結構就是將複雜的網絡通信過程按照一定的規則進行分層,從而能使整個的網絡通信過程更加清晰。

這一分層的核心思想有二:

1、每一層實現不同的功能,並對其上層做透明傳輸。

2、每一層都會使用到其下一層所提供的服務,並對其上一層提供服務。

 

早期的網絡體系結構是 OSI 七層模型:

1、物理層

2、數據鏈路層

3、網絡層

4、傳輸層

5、會話層

6、表示層

7、應用層。

但 OSI 模型在現在用的已經比較少了。通常這個 OSI 模型會和交換機比較相關。

 

現在用的較多的是 Internet 事實上的四層模型:

1、網絡接口和物理層

該層的主要作用是為了屏蔽硬件差異。無論你是通過什麼類型的硬件進行網絡通信的,在 Linux 內核中都會將它描述成是一個 net_device 結構體。

這一層有一個很重要的概念:MAC地址。

與這一層相關的比較常用的網絡協議有以下幾種:

1、ARP/RARP 協議

ARP 的作用是將根據IP地址找到對應的MAC地址,而 RARP 則相反。

2、PPP 協議

這就是我們常説的撥號協議。

2、網絡層

負責端到端的傳輸。簡單理解就是不同機器之間的數據傳輸,網絡層就負責將數據從一個機器準確抵達另一個機器上。

這一層也有一個很重要的概念:IP地址。

與這一層相關的比較常用的網絡協議有以下幾種:

1、IP協議

2、ICMP

Internet 控制管理協議。如 ping 命令。

3、IGMP

Internet 分組管理協議。如廣播、組播等。

3、傳輸層

負責分發數據到確定的任務去處理。

與這一層相關的比較常用的網絡協議有以下幾種:

1、TCP

面向連接的一對一的可靠數據傳輸協議。

何謂可靠傳輸呢?即數據無誤、數據無丟失、數據無錯序以及數據無重複地到達的傳輸。

TCP 是如何實現可靠傳輸的呢?

1、它會將所有數據進行編號,每一個字節編一個號;

2、它傳送數據是以一個 window 來進行的,並且有接收方的確認機制。

2、UDP

無連接的一對一的不可靠數據傳輸協議。

3、SCTP

流控制傳輸協議。它是一種可靠傳輸協議,它是 TCP  的增加版,它的可靠性要比 TCP 更好一些。

它能實現多主機、多鏈路的通信。

4、應用層

具體的應用程序對數據的消費。

與這一層相關的比較常用的網絡協議有以下幾種:

1、HTTP/HTTPS

網頁訪問協議。

2、POP3/SMTP/IMAP

郵件發送接收協議。 POP3用於發送,SMTP用於接收。

3、Telnet/SSH

遠程登錄協議。 Telnet 是明文傳輸的通信協議,SSH 是加密數據傳輸的。

4、NTP

網絡時鐘協議。

5、SNMP

簡單網絡管理協議,主要用於實現對網絡設備的集中式管理。

6、RTP/RTSP

主要用於傳輸音視頻的協議。

在 Linux 網絡系統中,無論是 OSI 七層模型還是四層模型,傳輸層及其以下的層級都是 Linux 內核的部分。其上的部分才是屬於應用空間的內容。

 

網絡通信過程中的封包與拆包:

懶得轉述,一圖勝千言。

Linux 下互聯網絡編程的基礎知識_IP_02

 

Socket :

首先 Socket 是一種編程接口,它同時也是一種特殊的文件描述符。

Socket 的類型有三種:

1、流式套接字:SOCK_STREAM  --> TCP

2、數據報套接字:SOCK_DGRAM  --> UDP

3、原始套接字:SOCK_RAW 

這一協議跨過了傳輸層,直接對網絡層進行 IP,ICMP 訪問。

 

IP地址:

分為 IPV4 與 IPV6。IPV4 使用 4 個字節共 32 位的整型數表示。IPV6 使用 16 個字節共 128 位的整型數表示。

 

IPV4:

通常 IPV4 地址會以適合閲讀的點分形式來表示,如:192.168.77.254。但在網絡通信裏,為了節省流量,通常會將點分形式的 IPV4 地址轉成 32 位的整型數值來表示。

Linux 系統提供了多種將點分形式IP地址轉換成整數形式的接口:

1、in_addr_t inet_addr(const char *cp); 

參數 cp 就是點分形式的 IPV4 地址。這個函數內部已經包含了字節序轉換操作的了。

這個函數只能轉換 IPV4 的地址,並且這個函數不能轉換 255.255.255.255 地址。

2、int inet_pton(int af, const char *src, void *dst);

這個函數可以轉換任意 IPV4 或 IPV6 地址。

返回值為 1 時表示轉換成功。

參數 af 指明地址協議族,可填 AF_INET 或 AF_INET6,分別對應於 IPV4 和 IPV6。

參數 src 是字符串形式的 IP 地址。

參數 dest 是轉換的結果。

3、const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

將整數形式的 IP 地址轉換成適宜閲讀的字符串形式。

執行成功時返回一個非空的 dst 的地址,執行失敗時返回 NULL 並設置相應的 errno。

參數 af 代表 IP 協議,可以填寫 AF_INET 或 AF_INET6。

參數 src 就是要轉換的整數形式的 IP 地址的地址。

參數 dst 通常就是 char * 地址。

參數 size 是 src 所代表的 sockaddr 結構體的大小。

 

特殊的 IPV4 地址:

局域網 IP:192.168.xxx.xxx , 172.16( ~ 31).xxx.xxx , 10.xxx.xxx.xxx

廣播 IP:xxx.xxx.xxx.255 , 255.255.255.255(全網廣播)

組播 IP:224.xxx.xxx.xxx ~ 239.xxx.xxx.xxx (所有以 255 結尾的 IPV4 地址都是廣播地址,不能實現組播功能。)

 

端口號:

端口號是一個 16 位的數字,範圍為 1 ~ 65535。

它的作用就是用於區分同一台機器中需要進行網絡通信的不同的任務。

TCP 端口與 UDP 端口是相互獨立的。即同一個端口號可以分別以 TCP 的形式和 UDP  的形式在系統中共存使用。

 

保留端口:

1 ~ 1023。這些端口號普通應用程序通常是無法使用的。

另外還有一組端口號是不建議普通應用程序使用但是卻是可以直接使用的: 1024 ~ 5000。

 

特殊端口號:

FTP : 21

SSH : 22

HTTP : 80

HTTPS : 469

 

字節序:

字節序的概念主要應用於多字節整數的情況。

字節序主要分兩種:

1、小端序;

2、大端序。

數據本身有低端數據與高端數據之分,如 0x123456789 ,數據 0x12 是高端數據,數據 0x89 是低端數據。

內存也有高低端之分。

當內存的低端存儲着數據的低端時,就稱為“小端序”。

當內存的低端存儲着數據的高端時,就稱為“大端序”。

 

通常 x86/arm 架構的機器都採用小端模式。而 powerpc/mips 或者説當 ARM 作為路由器時就採用大端模式。

當 CPU 訪問字符串時不存在大小端問題,字符串都是單字節構成的,不存在字節排序問題。

 

字節序在實際應用中又分為:1、本地字節序(小端序);2、網絡字節序(大端序)。兩種概念。Linux 系統也提供了這兩種字節序相互轉換的函數接口:

本地字節序 ---> 網絡字節序

u_long htonl(u_long hostlong);

u_short htons(u_short short);

網絡字節序 ---> 本地字節序

u_long ntohl(u_long hostlong);

u_short ntohs(u_short short);

 

常用的網絡信息檢索函數:

1、gethostname();

獲取主機名。

2、getpeername();

獲得與套接口相連的遠程協議地址。

3、getsockname();

獲得本地套接口協議地址。

4、gethostbyname();

根據主機名取得主機信息。

將域名形式的地址轉換成 IP 地址形式。

函數執行成功時返回一個結構體變量 struct hostent,它的原型如下:

struct hostent {

    char *h_name;

    char **h_aliases;

    int h_addrtype;

    int h_length;

    char **h_addr_list;

};

由於調用這個函數時系統會自動創建一個 hostent 結構體,這個結構體內部有多項指針。為了避免內存泄露,在結束地址信息使用時,應手動調用一下 endhostent() 函數。

5、gethostbyaddr();

根據主機地址取得主機信息。

6、getprotobyname();

根據協議名取得主機協議信息。

7、getprotobynumber();

根據協議號取得主機協議信息。

8、getservbyname();

根據服務名取得相關服務信息。

9、getservbyport();

根據端口號取得相關服務信息。

 

常用的網絡函數:

1、設置 socket 參數;

#include <sys/types.h>

#include <sys/socket.h>

int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

根據這兩個函數的名字也能猜到它們是與配置 socket 有關的函數了。

參數 level 用於指定控制套接字的層次,可選的值有三個:

1、SOL_SOCKET;  通用套接字選項。屬於應用層

2、IPPROTO_IP;  IP選項。屬於網絡層

3、IPPROTO_TCP; TCP選項。屬於傳輸層

參數 optname 表示選項。這個的可選值比較多,具體的可以查詢 man 手冊。

參數 optval 表示選項的值。與前一個參數息息相關,需要注意的是,不同的選項類型所對應的值的類型也不一樣,因此這裏會要求傳入一個無類型指針。具體的值類型需要參閲 man 手冊。

參數 optlen 就是前一個參數選項的值的長度了。通常使用 sizeof 就可以了。

 

廣播:

所謂廣播就是指同一個網絡包允許被多台主機接收到的網絡通信模式。廣播必須使用 UDP 協議。

 

每一個網段中最後一個 IP 地址就是廣播專屬地址,例如 192.168.1.x 網段,它的廣播地址就為 192.168.1.255,而 10.x.x.x 網段的廣播地址則為 10.255.255.255。另外,有一個特殊廣播地址:255.255.255.255,它表示全網廣播地址。

 

所謂廣播地址就是指當你向某個廣播地址發送數據包時,那麼該網段上的所有主機都可以接收到這個網絡包。但是對於 255.255.255.255 這個全網廣播地址,絕大多數的路由器都是禁用了這一廣播地址功能的。

 

廣播通信編程模型中也分發送方與接收方兩種角色,本質上就是 C/S 模型。

 

對於廣播發送方,它需要按以下步驟實現:

1、創建UDP套接字;

2、默認創建出來的套接字不允許廣播數據,它需要調用 setsockopt 設置一下套接字屬性;

int b_br = 1;

setsockopt(sockFd, SOL_SOCKET, SO_BROADCAST, &b_br, sizeof(int));

3、將接收方的地址指定為對應的廣播地址;

4、指定端口信息;

5、發送數據包。

 

對於廣播接收方,它需要按以下步驟實現:

1、創建UDP套接字;

2、綁定本機IP地址和指定的廣播通信端口;

3、等待接收數據。

 

組播:

 組播與廣播都屬於一對多的網絡通信模式。但與廣播不同,組播是在特定的“組”裏實現的一對多網絡通信。換句話説就是組播是一個人發送,所有加入到特定組裏的人才能接收到數據的通信模式。可以理解成是一種加了一些限定條件的廣播通信。

 

同樣的組播的通信也必須使用 UDP 協議。

 

組播的地址範圍在 IP 地址分類中屬於 D 類地址,它的範圍為:224.0.0.1 ~ 239.255.255.254,這個地址範圍中要注意所有以 255 結尾的地址都是廣播地址,不屬於組播的範疇。

 

組播的發送方通常需要按以下步驟實現:

1、創建UDP套接字;

2、將接收方地址設定為組播地址;

3、指定端口信息;

4、發送數據包。

 

組播的接收方通常需要按以下步驟實現:

1、創建 UDP 套接字;

2、加入特定的組播組;

struct ip_mreq mreq;

bzero(&mreq, sizeof(mreq));

mreq.imr_multiaddr.s_addr = inet_addr("233.5.6.100");

mreq.imr_interface.s_addr = htonl(INADDR_ANY);

setsockopt(socdFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

3、綁定本機IP地址和指定的端口號;

4、等待接收數據。