Linux网络编程——多播

转载 http://blog.csdn.net/tennysonsky/article/details/44493407#

概述
单播用于两个主机之间的端对端通信,广播用于一个主机对整个局域网上所有主机上的数据通信。单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。实际情况下,经常需要对一组特定的主机进行通信,而不是整个局域网上的所有主机,这就是多播的用途。

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 <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; // 多播地址结构体                                   
  
    // 加入多播组,相当于创建一个QQ群,某人加入此群  
    mreq.imr_multiaddr.s_addr = inet_addr(group); // 多播地址,类似于 QQ 群号   
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);// 将本机加入多播组,类似于某人加入此群  
    // 加入多播组  
    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;   
  
    // 循环接收广播组的消息,5次后退出  
    for(times = 0; times<5; times++)    
    {    
        addr_len = sizeof(local_addr);    
        memset(buff, 0, sizeof(buff));       
          
        // 接收数据   
        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;    
}   

以上代码编译运行时,可以会出现这样的错误:No such device。这主要和网络配置有关,解决方法请点此链接:http://blog.csdn.net/tennysonsky/article/details/49050579

向多播组发送信息的测试示例:


#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; // 目标ip  
    char buf[] = "BROADCAST TEST DATA";  
  
    sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 建立套接字  
    if (s == -1)  
    {  
        perror("socket()");  
        return -1;  
    }  
  
    // 初始化目标 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);   // 多播服务器的端口也是 8000  
  
    // 向多播地址发送数据  
    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;  
}  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容

  • 12.1 引言 在第1章中我们提到有三种IP地址:单播地址、广播地址和多播地址。本章将更详细地介绍广播和多播。 广...
    张芳涛阅读 767评论 0 4
  • 1.这篇文章不是本人原创的,只是个人为了对这部分知识做一个整理和系统的输出而编辑成的,在此郑重地向本文所引用文章的...
    SOMCENT阅读 13,028评论 6 174
  • 个人认为,Goodboy1881先生的TCP /IP 协议详解学习博客系列博客是一部非常精彩的学习笔记,这虽然只是...
    贰零壹柒_fc10阅读 5,042评论 0 8
  • 名词延伸 通俗的说,域名就相当于一个家庭的门牌号码,别人通过这个号码可以很容易的找到你。如果把IP地址比作一间房子...
    杨大虾阅读 20,572评论 2 57
  • 许多年之后,我走了 或许,我的诗会化作一个又一个蝴蝶 从我泛黄的诗卷里,飞出 飞满世界 或许,人们还会欣赏 或许,...
    吴生善阅读 144评论 0 0