Udp多播简介

概叙

  • 单播用于两个主机之间单对单的通信
  • 广播用于一个主机对整个局域网上所有主机上的数据通信
  • 单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网的主机进行通信
  • 实际情况下,经常需要对一组特定的主机进行通信,而不是所有局域网上的主机,这时候就有了组播
  • IP组播(也称多址广播或多播),是一种允许一台或多台主机发送数据包到多台主机的TCP/IP网路技术。
  • 多播是 IPv6 数据包的 3 种基本目的地址类型之一,多播是一点对多点的通信, IPv6 没有采用 IPv4 中的组播术语,而是将广播看成是多播的一个特殊例子。

组播应用

  • 一对多点应用:一对多点应用是指一个发送者,多个接收者的应用形式,这是最常见的多播应用形式。典型的应用包括:媒体广播、媒体推送、信息缓存、事件通知和状态监视等。
  • 多对一应用:多点对点应用是指多个发送者,一个接收者的应用形式。通常是双向请求响应应用,任何一端(多点或点)都有可能发起请求。典型应用包括:资源查找、数据收集、网络竞拍、信息询问等。
  • 多对多应用:多点对多点应用是指多个发送者和多个接收者的应用形式。通常,每个接收者可以接收多个发送者发送的数据,同时,每个发送者可以把数据发送给多个接收者。典型应用包括:多点会议、资源同步、并行处理、协同处理、远程学习、讨论组、分布式交互模拟(DIS)、多人游戏等。

组播地址

IP组播通信必须依赖于IP多播地址,在IPv4中它是一个D类IP地址,范围从 224.0.0.0239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:

  • 局部链接多播地址范围在 224.0.0.0~224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包;
  • 预留多播地址为 224.0.1.0~238.255.255.255,可用于全球范围(如Internet)或网络协议;
  • 管理权限多播地址为 239.0.0.0~239.255.255.255,可供组织内部使用,类似于私有 IP 地址,不能用于 Internet,可限制多播范围。

组播地址与MAC地址的映射

  • 使用同一个 IP 多播地址接收多播数据包的所有主机构成了一个主机组,也称为多播组。一个多播组的成员是随时变动的,一台主机可以随时加入或离开多播组,多播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个多播组。
  • 设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤,这个过滤过程是网络驱动或IP层自动完成。(设备驱动程序会对多播数据进行过滤,将其发到相应的位置)
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

// 接收组播地址为224.0.0.88  的信息
int main(int argc,char *argv[]){
    int socked=socket(AF_INET,SOCK_DGRAM,0);
    if(socked<0)
    {
        perror("socket failed!");
        return 2;
    }

    char group[16]="224.0.0.88";
   // char group_1[16]="224.0.0.66";


    struct sockaddr_in local_addr;
    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(8888);

    int ret = bind(socked, (struct sockaddr*)&local_addr, sizeof(local_addr));
    if(ret<0)
    {
        perror("bind failed !");
        return 3;
    }


    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(group);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

    /*
     *
     *  int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
     * param:
     *      optname
     *          * IP_MULTICAST_LOOP 支持多播数据回送
     *          * IP_ADD_MEMBERSHIP 加入多播组
     *          * IP_DROP_MEMBERSHIP 离开多播组
     *      optval
     *          * IP_MULTICAST_LOOP 选项对应传入 unsigned int 来确认是否支持多播数据回送
     *          * IP_ADD_MEMBERSHIP 传入 ip_mreq
     *          * IP_DROP_MEMBERSHIP 传入 ip_mreq
     *
     * */
    ret=setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
    if(ret<0){
        perror("setsockopt failed !");
        return 3;
    }else
    {
        printf("setsockopt success\n");
    }


    char buf[1024];
    int length=0;
    struct sockaddr_in sender;
    socklen_t sender_len=sizeof(sender);
    while (true){
        memset(buf, 0, sizeof(buf));
        length=recvfrom(socked, buf, sizeof(buf), 0, (struct sockaddr*)&sender,&sender_len);
        buf[length]='\0';
        printf("%s %d : %s\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port),buf);
    }
    setsockopt(socked, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
    close(socked);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

//向组播地址为224.0.0.88的组发送信息
int main() {
    char group_addr[16]="224.0.0.88";
    int socked=socket(AF_INET,SOCK_DGRAM,0);
    if(socked<0)
    {
        perror("socket failed!");
        return 2;
    }

    struct sockaddr_in remote_addr;
    memset(&remote_addr,0,sizeof(remote_addr));

    remote_addr.sin_family=AF_INET;
    remote_addr.sin_addr.s_addr=inet_addr(group_addr);
    remote_addr.sin_port=htons(8888);

    char buf[1024]="This is a group udp";
    int length=0;
    while(1)
    {
        length=sendto(socked,buf,strlen(buf),0,(struct sockaddr *)&remote_addr,sizeof(remote_addr));
        printf("Send Message%s\n",buf);
    }
    close(socked);
    return 0;
}