【Linux网络编程】多播、组播
概述
單播用于兩個主機之間的端對端通信,廣播用于一個主機對整個局域網上所有主機上的數據通信。單播和廣播是兩個極端,要么對一個主機進行通信,要么對整個局域網上的主機進行通信。實際情況下,經常需要對一組特定的主機進行通信,而不是整個局域網上的所有主機,這就是多播的用途。
IP 多播(也稱多址廣播或組播)技術,是一種允許一臺或多臺主機(多播源)發送單一數據包到多臺主機(一次的,同時的)的 TCP/IP 網絡技術。多播是 IPv6 數據包的 3 種基本目的地址類型之一,多播是一點對多點的通信, IPv6 沒有采用 IPv4 中的組播術語,而是將廣播看成是多播的一個特殊例子。
多播作為一點對多點的通信,數據的收發僅僅在同一分組中進行,是節省網絡帶寬的有效方法之一。在網絡應用中,當需要將一個節點的信號傳送到多個節點時,無論是采用重復點對點通信方式,還是采用廣播方式,都會嚴重浪費網絡帶寬,只有多播才是最好的選擇。多播能使一個或多個多播源只把數據包發送給特定的多播組,而只有加入該多播組的主機才能接收到數據包。
IP 多播應用大致可以分為三類:點對多點應用,多點對點應用和多點對多點應用。
1)點對多點應用是指一個發送者,多個接收者的應用形式,這是最常見的多播應用形式。典型的應用包括:媒體廣播、媒體推送、信息緩存、事件通知和狀態監視等。
2)多點對點應用是指多個發送者,一個接收者的應用形式。通常是雙向請求響應應用,任何一端(多點或點)都有可能發起請求。典型應用包括:資源查找、數據收集、網絡競拍、信息詢問等。
3)多點對多點應用是指多個發送者和多個接收者的應用形式。通常,每個接收者可以接收多個發送者發送的數據,同時,每個發送者可以把數據發送給多個接收者。典型應用包括:多點會議、資源同步、并行處理、協同處理、遠程學習、討論組、分布式交互模擬(DIS)、多人游戲等。
多播地址
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 網絡時間協議
多播地址與 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層自動完成。
Linux多播編程
套接口選項
int setsockopt( int sockfd, int level,int optname, ??
const void *optval, socklen_t optlen );
成功執行返回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。
加入多播實例:
#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; }
發送方測試結果如下:
接收方測試結果如下:
總結
以上是生活随笔為你收集整理的【Linux网络编程】多播、组播的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【SDL】SDL学习笔记一 SDL的子系
- 下一篇: 【Linux网络编程】Linux多播问题