轉(zhuǎn)載 http://blog.csdn.net/tennysonsky/article/details/44493407#
概述
單播用于兩個(gè)主機(jī)之間的端對(duì)端通信,廣播用于一個(gè)主機(jī)對(duì)整個(gè)局域網(wǎng)上所有主機(jī)上的數(shù)據(jù)通信湘捎。單播和廣播是兩個(gè)極端垦江,要么對(duì)一個(gè)主機(jī)進(jìn)行通信,要么對(duì)整個(gè)局域網(wǎng)上的主機(jī)進(jìn)行通信。實(shí)際情況下钩述,經(jīng)常需要對(duì)一組特定的主機(jī)進(jìn)行通信,而不是整個(gè)局域網(wǎng)上的所有主機(jī)穆碎,這就是多播的用途牙勘。
IP 多播(也稱多址廣播或組播)技術(shù),是一種允許一臺(tái)或多臺(tái)主機(jī)(多播源)發(fā)送單一數(shù)據(jù)包到多臺(tái)主機(jī)(一次的所禀,同時(shí)的)的 TCP/IP 網(wǎng)絡(luò)技術(shù)方面。多播是 IPv6 數(shù)據(jù)包的 3 種基本目的地址類型之一,多播是一點(diǎn)對(duì)多點(diǎn)的通信, IPv6 沒有采用 IPv4 中的組播術(shù)語色徘,而是將廣播看成是多播的一個(gè)特殊例子恭金。
多播作為一點(diǎn)對(duì)多點(diǎn)的通信,數(shù)據(jù)的收發(fā)僅僅在同一分組中進(jìn)行褂策,是節(jié)省網(wǎng)絡(luò)帶寬的有效方法之一横腿。在網(wǎng)絡(luò)應(yīng)用中,當(dāng)需要將一個(gè)節(jié)點(diǎn)的信號(hào)傳送到多個(gè)節(jié)點(diǎn)時(shí)斤寂,無論是采用重復(fù)點(diǎn)對(duì)點(diǎn)通信方式耿焊,還是采用廣播方式,都會(huì)嚴(yán)重浪費(fèi)網(wǎng)絡(luò)帶寬遍搞,只有多播才是最好的選擇罗侯。多播能使一個(gè)或多個(gè)多播源只把數(shù)據(jù)包發(fā)送給特定的多播組,而只有加入該多播組的主機(jī)才能接收到數(shù)據(jù)包溪猿。
IP 多播應(yīng)用大致可以分為三類:點(diǎn)對(duì)多點(diǎn)應(yīng)用钩杰,多點(diǎn)對(duì)點(diǎn)應(yīng)用和多點(diǎn)對(duì)多點(diǎn)應(yīng)用。
1)點(diǎn)對(duì)多點(diǎn)應(yīng)用是指一個(gè)發(fā)送者诊县,多個(gè)接收者的應(yīng)用形式讲弄,這是最常見的多播應(yīng)用形式。典型的應(yīng)用包括:媒體廣播依痊、媒體推送避除、信息緩存、事件通知和狀態(tài)監(jiān)視等抗悍。
2)多點(diǎn)對(duì)點(diǎn)應(yīng)用是指多個(gè)發(fā)送者,一個(gè)接收者的應(yīng)用形式钳枕。通常是雙向請(qǐng)求響應(yīng)應(yīng)用缴渊,任何一端(多點(diǎn)或點(diǎn))都有可能發(fā)起請(qǐng)求。典型應(yīng)用包括:資源查找鱼炒、數(shù)據(jù)收集衔沼、網(wǎng)絡(luò)競拍、信息詢問等。
3)多點(diǎn)對(duì)多點(diǎn)應(yīng)用是指多個(gè)發(fā)送者和多個(gè)接收者的應(yīng)用形式指蚁。通常菩佑,每個(gè)接收者可以接收多個(gè)發(fā)送者發(fā)送的數(shù)據(jù),同時(shí)凝化,每個(gè)發(fā)送者可以把數(shù)據(jù)發(fā)送給多個(gè)接收者稍坯。典型應(yīng)用包括:多點(diǎn)會(huì)議、資源同步搓劫、并行處理瞧哟、協(xié)同處理、遠(yuǎn)程學(xué)習(xí)枪向、討論組勤揩、分布式交互模擬(DIS)、多人游戲等秘蛔。
多播地址
IP 多播通信必須依賴于 IP 多播地址陨亡,在 IPv4 中它是一個(gè) D 類 IP 地址,范圍從 224.0.0.0 到 239.255.255.255深员,并被劃分為局部鏈接多播地址负蠕、預(yù)留多播地址和管理權(quán)限多播地址三類:
1)局部鏈接多播地址范圍在 224.0.0.0~224.0.0.255,這是為路由協(xié)議和其它用途保留的地址辨液,路由器并不轉(zhuǎn)發(fā)屬于此范圍的IP包虐急;
2)預(yù)留多播地址為 224.0.1.0~238.255.255.255,可用于全球范圍(如Internet)或網(wǎng)絡(luò)協(xié)議滔迈;
3)管理權(quán)限多播地址為 239.0.0.0~239.255.255.255止吁,可供組織內(nèi)部使用,類似于私有 IP 地址燎悍,不能用于 Internet敬惦,可限制多播范圍。
一些多播組地址被 IANA 確定為知名地址谈山,它們也被當(dāng)作永久主機(jī)組俄删,這和 TCP 及 UDP 中的知名端口相似。同樣奏路,這些知名多播地址在 RFC 最新分配數(shù)字中列出畴椰,注意這些多播地址所代表的組是永久組,而它們的組成員卻不是永久的鸽粉。這些地址如下:
224.0.0.1 所有組播主機(jī)
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 網(wǎng)絡(luò)時(shí)間協(xié)議
多播地址與 MAC 地址的映射
使用同一個(gè) IP 多播地址接收多播數(shù)據(jù)包的所有主機(jī)構(gòu)成了一個(gè)主機(jī)組斜脂,也稱為多播組。一個(gè)多播組的成員是隨時(shí)變動(dòng)的触机,一臺(tái)主機(jī)可以隨時(shí)加入或離開多播組帚戳,多播組成員的數(shù)目和所在的地理位置也不受限制玷或,一臺(tái)主機(jī)也可以屬于幾個(gè)多播組。
這個(gè)我們可以這樣理解片任,多播地址就類似于 QQ 群號(hào)偏友,多播組相當(dāng)于 QQ 群,一個(gè)個(gè)的主機(jī)就相當(dāng)于群里面的成員对供。
** IPv4 的 D 類地址是多播地址**位他。IEEE 把一塊以太網(wǎng)多播組地址分給 IANA 以支持IP多播。塊的地址都以 01:00:5e 開頭犁钟,第 25 位為 0棱诱,低 23 位為 IPv4 多播地址( D類地址 )的低 23 位。IPv4 多播地址與 MAC 地址的映射關(guān)系如圖所示:
由于多播地址( D類地址 )中的最高 5bit 在映射過程中被忽略涝动,因此每個(gè)以太網(wǎng)多播地址對(duì)應(yīng)的多播組是不唯一的迈勋。32 個(gè)不同的多播組號(hào)被映射為一個(gè)以太網(wǎng)地址。例如醋粟,多播地址 224.128.64.32(十六進(jìn)制 e0.80.40.20)和 224.0.64.32(十六進(jìn)制 e0.00.40.20)都映射為同一以太網(wǎng)地址 01:00:5e:00:40:20靡菇。
既然地址映射是不唯一的,那么設(shè)備驅(qū)動(dòng)程序或 IP 層就必須對(duì)數(shù)據(jù)報(bào)進(jìn)行過濾米愿。因?yàn)榫W(wǎng)卡可能接收到主機(jī)不想接收的多播數(shù)據(jù)幀厦凤,如下圖,假如主機(jī) 1 加入的多播為 224.128.64.32育苟, 主機(jī) 2 加入的多播為 224.0.64.32较鼓,我們想給 224.0.64.32 所在的多播組 ( 主機(jī) 2 ) 發(fā)送信息,數(shù)據(jù)經(jīng)過網(wǎng)卡時(shí)违柏,224.128.64.32 (主機(jī) 1 ) 和 224.0.64.32 (主機(jī) 2 ) 所在多播組的網(wǎng)卡都會(huì)收到數(shù)據(jù)博烂,因?yàn)樗鼈兊?MAC 地址都是 01:00:5e:00:40:20。這時(shí)候漱竖,如果網(wǎng)卡不提供足夠的多播數(shù)據(jù)幀過濾功能禽篱,設(shè)備驅(qū)動(dòng)程序就必須接收所有多播數(shù)據(jù)幀,然后對(duì)它們進(jìn)行過濾馍惹,這個(gè)過濾過程是網(wǎng)絡(luò)驅(qū)動(dòng)或IP層自動(dòng)完成躺率。
Linux多播編程
套接口選項(xiàng)
**int setsockopt( int sockfd, int level,int optname, **
**const void *optval, socklen_t optlen );**
成功執(zhí)行返回0,否則返回-1
選項(xiàng) IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP
加入或者退出一個(gè)多播組万矾,通過選項(xiàng) IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP悼吱,對(duì)一個(gè)結(jié)構(gòu) struct ip_mreq 類型的變量進(jìn)行控制,struct ip_mreq 原型如下:
struct in_addr{
in_addr_t s_addr;
}
struct ip_mreq
{
struct in_addr imn_multiaddr; // 多播組 IP良狈,類似于 QQ 群號(hào)
struct in_addr imr_interface; // 將要添加到多播組的 IP后添,類似于QQ 成員號(hào)
};
多播只能用 UDP 或原始 IP 實(shí)現(xiàn),不能用 TCP们颜。
加入多播實(shí)例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
int main(int argc, char*argv[])
{
int sockfd; // 套接字文件描述符
struct sockaddr_in local_addr; // 本地地址
int err = -1;
char group[16] = "224.0.0.88"; // 多播組 IP
sockfd = socket(AF_INET, SOCK_DGRAM, 0); //建立套接字
if (sockfd == -1)
{
perror("socket()");
return -1;
}
// 初始化地址
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(8000);
// 綁定socket
err = bind(sockfd,(struct sockaddr*)&local_addr, sizeof(local_addr));
if(err < 0)
{
perror("bind()");
return -2;
}
struct ip_mreq mreq; // 多播地址結(jié)構(gòu)體
// 加入多播組吕朵,相當(dāng)于創(chuàng)建一個(gè)QQ群,某人加入此群
mreq.imr_multiaddr.s_addr = inet_addr(group); // 多播地址窥突,類似于 QQ 群號(hào)
mreq.imr_interface.s_addr = htonl(INADDR_ANY);// 將本機(jī)加入多播組努溃,類似于某人加入此群
// 加入多播組
err = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq));
if (err < 0)
{
perror("setsockopt():IP_ADD_MEMBERSHIP");
return -4;
}
int times = 0;
int addr_len = 0;
char buff[256] = {0};
int n = 0;
// 循環(huán)接收廣播組的消息,5次后退出
for(times = 0; times<5; times++)
{
addr_len = sizeof(local_addr);
memset(buff, 0, sizeof(buff));
// 接收數(shù)據(jù)
n = recvfrom(sockfd, buff, sizeof(buff), 0,(struct sockaddr*)&local_addr, &addr_len);
if( n== -1)
{
perror("recvfrom()");
}
printf("Recv %dst message from server:%s\n", times, buff);
sleep(2);
}
// 退出廣播組
err = setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
close(sockfd);
return 0;
}
以上代碼編譯運(yùn)行時(shí)阻问,可以會(huì)出現(xiàn)這樣的錯(cuò)誤:No such device梧税。這主要和網(wǎng)絡(luò)配置有關(guān),解決方法請(qǐng)點(diǎn)此鏈接:http://blog.csdn.net/tennysonsky/article/details/49050579称近。
向多播組發(fā)送信息的測試示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
int main(int argc, char*argv)
{
int sockfd; // 套接字文件描述符
struct sockaddr_in dest_addr; // 目標(biāo)ip
char buf[] = "BROADCAST TEST DATA";
sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 建立套接字
if (s == -1)
{
perror("socket()");
return -1;
}
// 初始化目標(biāo) ip 信息
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr("224.0.0.88"); // 目的地址第队,為多播地址
dest_addr.sin_port = htons(8000); // 多播服務(wù)器的端口也是 8000
// 向多播地址發(fā)送數(shù)據(jù)
while(1){
int n = sendto(sockfd, buf, strlen(buf), 0,(struct sockaddr*)&dest_addr, sizeof(dest_addr));
if( n < 0)
{
perror("sendto()");
return -2;
}
sleep(1);
}
return 0;
}