UNP学习_组播服务器与客户端的实现

UNP学习_组播服务器与客户端的实现

1.1 组播概述

  组播是一种介于单播和广播之间的方案,多播地址表示一组主机IP接口,多拨数据报只由对他感兴趣的接口接收。组播可以在Internet和局域网使用。一个多播地址和一个UDP端口的组合称为组播会话(session)。

1.2 组播地址

1.2.1 IPv4的D类地址
  IPv4的D类地址(224.0.0.0到239.255.255.255)是IPv4的组播地址。D类地址的低28位称为组ID(group ID),完整32位称为组地址(group address)。下面是几个特殊的IPv4组播地址:
(1)224.0.0.1是所有节点组。子网上所有具有组播能力的节点(主机、路由器等)必须在具有组播能力的接口上加入该组。
(2)224.0.0.2是所有路由器组。子网上所有组播路由器必须在具有多播能力的接口上加入该组。
(3)介于224.0.0.0到224.0.0.255之间的地址(224.0.0.0/24)称为链路局部的组播地址,这些地址为低级拓扑发现和维护协议保留,路由器冲不转发以这些地址为目的地址的数据报。

1.2.2 IPv6组播地址
  IPv6的组播地址的高字节值为ff。IPv6的组播地址有2种格式,详见UNP434页。下面是两个特殊的IPv6组播地址
(1)ff01::1和ff02::1是所有节点组。
(2)ff01::2、ff02::2和ff05::2是所有路由器组
IPV6组播地址还存在一个4位的范围,用于指定组播数据报能够游走的范围。还有一个跳限字段,用于限制分组被路由转发的次数。

UNP学习_组播服务器与客户端的实现_第1张图片

UNP学习_组播服务器与客户端的实现_第2张图片
1.3 局域网上的组播示例
UNP学习_组播服务器与客户端的实现_第3张图片
  右侧主机上的接收进程启动,并创建一个UDP套接字,捆绑端口123到该套接字上,然后加入多播组224.0.1.1。IPv4层内部保存这些信息,并告知合适的数据链路接收目的地址为01:00:53:00:01:01的以太网帧。该地址是与接收应用进程加入的组播IP地址对应的以太网地址,映射方法如21-1图所示,此处详细情况见UNP的P437。

2.1 局域网UDP组播服务器的实现

// File Name: multicast_server.c
// Author: AlexanderGan
// Created Time: 2020年08月11日 星期二 19时57分33秒

#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(int argc, char*argv[]){

    int fd = socket(AF_INET,SOCK_DGRAM,0);

    if(fd < 0){
        perror("socket error!\n");
        exit(1);
    }

    struct sockaddr_in serv_addr, client_addr;
    socklen_t serv_len = sizeof(serv_addr);
    socklen_t cli_len = sizeof(client_addr);
    
    memset(&serv_addr,0,serv_len);
    memset(&client_addr,0,cli_len);
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(4321);//server端口

    int ret = bind(fd,(struct sockaddr*)&serv_addr,serv_len);

    if(ret < 0){
        perror("bind error!\n");
        exit(1);
    }
    //初始化客户端信息
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(2222);//客户端需要绑定的端口
    //组播需要的地址
    inet_pton(AF_INET,"239.0.0.10", &client_addr.sin_addr.s_addr);

    //打开服务器组播权限
    struct ip_mreqn flag;
    //init flag
    inet_pton(AF_INET,"239.0.0.10",&flag.imr_multiaddr.s_addr);//广播地址
    inet_pton(AF_INET,"0.0.0.0",&flag.imr_address.s_addr);//本地IP
    flag.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd,IPPROTO_IP, IP_MULTICAST_IF,&flag,sizeof(flag));
    //通信
    while(1){
        //持续给客户端广播数据
        static int num = 0;

        char buf[4096] = {0};
        sprintf(buf,"hello ,udp_id == %d\n",num++);

        int send_len = sendto(fd,buf,sizeof(buf),0,(struct sockaddr*)&client_addr,cli_len);
        if(send_len < 0){
            perror("send error!\n");
            exit(1);
        }

        printf("send buf = %s\n",buf);
        sleep(1);

        /*char ip[64];
        printf("New Client IP : %s, port = %d\n",
                inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ip,sizeof(ip)),
                ntohs(client_addr.sin_port));

        sendto(fd,buf,strlen(buf)+1,0,(struct sockaddr*)&client_addr,cli_len);*/

    }
    close(fd);
    return 0 ;
}

3.1 局域网UDP组播客户端的实现

// File Name: multicast_client.c
// Author: AlexanderGan
// Created Time: 2020年08月16日 星期日 19时06分28秒
// 组播客户端

#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char*argv[]){

    int fd = socket(AF_INET,SOCK_DGRAM,0);

    if(fd < 0){
        perror("socket error!\n");
        exit(1);
    }
    //绑定IP和端口
    struct sockaddr_in serv_addr, client_addr;
    socklen_t serv_len = sizeof(serv_addr);
    socklen_t cli_len = sizeof(client_addr);
    
    memset(&client_addr,0,cli_len);
    client_addr.sin_family = AF_INET;    
    client_addr.sin_port = htons(2222);
    inet_pton(AF_INET,"0.0.0.0",&client_addr.sin_addr.s_addr);  

    int ret = bind(fd,(struct sockaddr*)&client_addr,cli_len);
    if(ret < 0){
        perror("bind error!\n");
        exit(1);
    }

    //加入到组播地址
    struct ip_mreqn flag;
    inet_pton(AF_INET,"239.0.0.10",&flag.imr_multiaddr.s_addr);
    inet_pton(AF_INET,"0.0.0.0",&flag.imr_address.s_addr);
    flag.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&flag,sizeof(flag));

    //通信
    while(1){
        char buf[1024];
        int recv = recvfrom(fd,buf,sizeof(buf),0,NULL,NULL);

        if(recv < 0) {
            perror("recv error!\n");
            break;
        }

        printf("client recv buf =%s\n",buf);
    }

    close(fd);
    return 0;
}

4.1 组播的优点:
(1)组播利用多数网卡都提供的硬件过滤减少非期望分组的接收,硬件过滤在链路层就丢弃掉非期望的数据,还降低了不参与多播应用的系统的其他主机的负荷。
(2)组播可以在局域网上使用,也可以在因特网上使用。

你可能感兴趣的:(Linux网络编程,路由器,局域网,以太网)