【Linux网络编程】组播
00. 目錄
文章目錄
- 00. 目錄
- 01. 組播概述
- 02. 組播應用分類
- 03. 組播地址
- 04. 組播地址與 MAC 地址的關系
- 05. 套接字選項
- 06. 程序示例
- 07. 附錄
01. 組播概述
單播用于兩個主機之間的端對端通信,廣播用于一個主機對整個局域網上所有主機上的數據通信。單播和廣播是兩個極端,要么對一個主機進行通信,要么對整個局域網上的主機進行通信。實際情況下,經常需要對一組特定的主機進行通信,而不是整個局域網上的所有主機,這就是多播的用途。
IP 多播(也稱多址廣播或組播)技術,是一種允許一臺或多臺主機(多播源)發送單一數據包到多臺主機(一次的,同時的)的 TCP/IP 網絡技術。多播是 IPv6 數據包的 3 種基本目的地址類型之一,多播是一點對多點的通信, IPv6 沒有采用 IPv4 中的組播術語,而是將廣播看成是多播的一個特殊例子。
多播作為一點對多點的通信,數據的收發僅僅在同一分組中進行,是節省網絡帶寬的有效方法之一。在網絡應用中,當需要將一個節點的信號傳送到多個節點時,無論是采用重復點對點通信方式,還是采用廣播方式,都會嚴重浪費網絡帶寬,只有多播才是最好的選擇。多播能使一個或多個多播源只把數據包發送給特定的多播組,而只有加入該多播組的主機才能接收到數據包。
02. 組播應用分類
IP 多播應用大致可以分為三類: 點對多點應用,多點對點應用和多點對多點應用。
1)點對多點應用是指一個發送者,多個接收者的應用形式,這是最常見的多播應用形式。典型的應用包括:媒體廣播、媒體推送、信息緩存、事件通知和狀態監視等。
2)多點對點應用是指多個發送者,一個接收者的應用形式。通常是雙向請求響應應用,任何一端(多點或點)都有可能發起請求。典型應用包括:資源查找、數據收集、網絡競拍、信息詢問等。
3)多點對多點應用是指多個發送者和多個接收者的應用形式。通常,每個接收者可以接收多個發送者發送的數據,同時,每個發送者可以把數據發送給多個接收者。典型應用包括:多點會議、資源同步、并行處理、協同處理、遠程學習、討論組、分布式交互模擬(DIS)、多人游戲等。
03. 組播地址
IP 多播通信必須依賴于 IP 多播地址,在 IPv4 中它是一個 D 類 IP 地址,范圍從 224.0.0.0 到 239.255.255.255,并被劃分為局部鏈接多播地址、預留多播地址和管理權限多播地址三類:
1)局部鏈接多播地址范圍在 224.0.0.0~224.0.0.255,這是為路由協議和其它用途保留的地址,路由器并不轉發屬于此范圍的IP包;
2)預留多播地址為 224.0.1.0~238.255.255.255,可用于全球范圍(如Internet)或網絡協議;
3)管理權限多播地址為 239.0.0.0~239.255.255.255,可供組織內部使用,類似于私有 IP 地址,不能用于 Internet,可限制多播范圍。
一些多播組地址被 IANA 確定為知名地址,它們也被當作永久主機組,這和 TCP 及 UDP 中的知名端口相似。同樣,這些知名多播地址在 RFC 最新分配數字中列出,注意這些多播地址所代表的組是永久組,而它們的組成員卻不是永久的。這些地址如下:
224.0.0.1 所有組播主機
224.0.0.2 所有組播路由器
224.0.0.4 DRMRP 路由器
224.0.0.5 所有 OSPF 的路由器
224.0.0.6 OSPF 指派路由器
224.0.0.9 RPIv2 路由器
224.0.0.10 EIGRP 路由器
224.0.0.13 PIM 路由器
224.0.0.22 IGMPv3
224.0.0.25 RGMP
224.0.1.1 NTP 網絡時間協議
04. 組播地址與 MAC 地址的關系
使用同一個 IP 多播地址接收多播數據包的所有主機構成了一個主機組,也稱為多播組。一個多播組的成員是隨時變動的,一臺主機可以隨時加入或離開多播組,多播組成員的數目和所在的地理位置也不受限制,一臺主機也可以屬于幾個多播組。
這個我們可以這樣理解,多播地址就類似于 QQ 群號,多播組相當于 QQ 群,一個個的主機就相當于群里面的成員。
IPv4 的 D 類地址是多播地址。IEEE 把一塊以太網多播組地址分給 IANA 以支持IP多播。塊的地址都以 01:00:5e 開頭,第 25 位為 0,低 23 位為 IPv4 多播地址( D類地址 )的低 23 位。IPv4 多播地址與 MAC 地址的映射關系如圖所示:
由于多播地址( D類地址 )中的最高 5bit 在映射過程中被忽略,因此每個以太網多播地址對應的多播組是不唯一的。32 個不同的多播組號被映射為一個以太網地址。例如,多播地址 224.128.64.32(十六進制 e0.80.40.20)和 224.0.64.32(十六進制 e0.00.40.20)都映射為同一以太網地址 01:00:5e:00:40:20。
既然地址映射是不唯一的,那么設備驅動程序或 IP 層就必須對數據報進行過濾。因為網卡可能接收到主機不想接收的多播數據幀,如下圖,假如主機 1 加入的多播為 224.128.64.32, 主機 2 加入的多播為 224.0.64.32,我們想給 224.0.64.32 所在的多播組 ( 主機 2 ) 發送信息,數據經過網卡時,224.128.64.32 (主機 1 ) 和 224.0.64.32 (主機 2 ) 所在多播組的網卡都會收到數據,因為它們的 MAC 地址都是 01:00:5e:00:40:20。這時候,如果網卡不提供足夠的多播數據幀過濾功能,設備驅動程序就必須接收所有多播數據幀,然后對它們進行過濾,這個過濾過程是網絡驅動或IP層自動完成。
05. 套接字選項
setsockopt函數
int setsockopt( int sockfd, int level, int optname,const void *optval, socklen_t optlen); 功能:設置套接字選項參數:sockfd 套接字level IPPROTO_IPoptname IP_MULTICAST_LOOP 禁止多播數據回送IP_ADD_MEMBERSHIP 加入多播組IP_DROP_MEMBERSHIP 離開多播組optval 一般是int類型或者結構體類型optlen optval所指向類型的字節大小返回值:成功執行返回0,否則返回-1選項 IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP
加入或者退出一個多播組,通過選項 IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP,對一個結構 struct ip_mreq 類型的變量進行控制,struct ip_mreq 原型如下:
struct in_addr {in_addr_t s_addr; }struct ip_mreq { struct in_addr imn_multiaddr; // 多播組 IP,類似于 QQ 群號struct in_addr imr_interface; // 將要添加到多播組的 IP,類似于QQ 成員號 };溫馨提示
多播只能用 UDP 或原始 IP 實現,不能用 TCP。
06. 程序示例
加入多播示例
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>#define PORT 10086 #define SIZE 128int main(void) {int ret = -1;int sockfd = -1;int i = 0;char buf[SIZE];struct sockaddr_in addr;struct sockaddr_in from;//組播相關結構體struct ip_mreq req;socklen_t len = sizeof(from);sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("socket"); goto err0;}memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = INADDR_ANY;//inet_pton(AF_INET, "172.16.1.88", &addr.sin_addr); ret = bind(sockfd, (void*)&addr, sizeof(addr));if (-1 == ret){perror("bind"); goto err1;}printf("UDP Server %s: %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));//加入多播組req.imr_multiaddr.s_addr = inet_addr("224.0.0.88");//將本機加入多播組req.imr_interface.s_addr = INADDR_ANY;//加入多播組ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req));if (ret < 0){perror("setsockopt"); goto err0;}while(1){memset(buf, 0, SIZE);ret = recvfrom(sockfd, buf, SIZE, 0, (void*)&from, &len);buf[ret] = 0;printf("recv from: %s:%d %s\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port), buf);i++;//退出循環if (10 == i)break;}ret = setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &req, sizeof(req));if (ret < 0){perror("setsockopt"); goto err0;}//退出組播組之后 測試是否可以收到組播包while(1){memset(buf, 0, SIZE);ret = recvfrom(sockfd, buf, SIZE, 0, (void*)&from, &len);buf[ret] = 0;printf("recv from: %s:%d %s\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port), buf);i++;//退出循環if (10 == i)break;}close(sockfd);return 0; err1:close(sockfd); err0:return -1; }運行結果出錯如下:
以上代碼編譯運行時,可以會出現這樣的錯誤:No such device。這主要和網絡配置有關,
解決方法請點此鏈接:http://blog.csdn.net/dengjin20104042056/article/details/52357157。
向多播組發送信息的測試示例
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>#define PORT 10086 #define SIZE 128int main(void) {int ret = -1;int sockfd = -1;int i = 0;char buf[SIZE];struct sockaddr_in peer;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("socket"); goto err0;}memset(&peer, 0, sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = htons(PORT);inet_pton(AF_INET, "224.0.0.88", &peer.sin_addr); printf("send data to UDP Server %s: %d\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));//向多播組發送消息while(1){sprintf(buf, "hello world %d", i); ret = sendto(sockfd, buf, strlen(buf), 0, (void*)&peer, sizeof(peer));printf("ret: %d\n", ret);sleep(1);i++; }return 0; err0:return -1; }07. 附錄
7.1 【Linux】一步一步學Linux網絡編程教程匯總
總結
以上是生活随笔為你收集整理的【Linux网络编程】组播的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Linux网络编程】广播
- 下一篇: 【Linux网络编程】TCP编程