zoukankan      html  css  js  c++  java
  • multicast based on udp

    1.概念

    单播,是用于两个主机之间传送数据;

    广播,是一个主机对局域网内的所有主机发送数据;

    多播,又称为组播,它是对一组特定的主机通信。

      将网络上同一类型业务逻辑上分组,只和组内的成员通信,其它主机没有加入组则不能通信。与单播相同的是,组播允许在Internet上通信,而广播只是同一局域网内的主机通信。组播地址是特定的,D类地址用于组播,即244.0.0.0到239.255.255.255. 并划分为局部连接多播地址,预留多播地址和管理权限多播地址3类。

      (1)局部多播地址 (224.0.0.-224.0.0.255)为路由协议和其它用途保留的地址,路由器不转发此范围的IP包

      (2)预留多播地址   (224.0.1.0-238.255.255.255)可用于全球范围内或网络协议

      (3)管理权限的多播 (239.0.0.0-239.255.255.255) 可供组织内使用,类型于私有IP,不用于Internet,可限制多播范围

    2. 多播套接字设置

    可用setsockopt或getsockopt设置或得到多播选项. 常用的多播选项如下所示:

    IP_MULTICAST_TTL    设置多播的TTL值

      Sets the Time To Live (TTL) in the IP header for outgoing multicast datagrams.  By default it is set to 1.  TTL of 0 are not transmitted on any sub-network.  Multicast datagrams with a TTL of greater than 1 may be delivered to more than one sub-network, if there are one or more multicast routers attached to the first sub-network.

    IP_MULTICAST_IF      获取或设置多播接口

      Sets the interface over which outgoing multicast datagrams are sent.

    IP_MULTICAST_LOOP   禁止多播数据回送到本地loop接口

      Specifies whether or not a copy of an outgoing multicast datagram is delivered to the sending host as long as it is a member of the multicast group.

    IP_ADD_MEMBERSHIP   将指定的接口加入多播

       Joins the multicast group specified.

    IP_DROP_MEMBERSHIP  退出多播组

       Leaves the multicast group specified.

    struct ip_mreq{
      struct in_addr imn_multicastaddr;//多播组地址
      struct in_addr imr_interface;//加入的接口的IP地址
    }

    int ttl=255;
    setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));//设置跳数
    s-套接字描述符
    PROTO_IP-选项所在的协议层
    IP_MULTICAST_TTL-选项名
    &ttl-设置的内存缓冲区
    sizeof(ttl)-设置的内存缓冲区长度

    struct in_addr in;
    setsockopt(s,IPPROTO_IP,IP_MUTLICAST_IF,&in,sizeof(in));//设置组播接口

    int yes=1;
    setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&yes,sizeof(yes));//设置数据回送到本地回环接口

    struct ip_mreq addreq;
    setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&req,sizeof(req));//加入组播组

    struct ip_mreq dropreq;
    setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,&dropreq,sizeof(dropreq));//离开组播组

    3. 多播程序的设计流程

    (1)建立socket

    (2)设置TTL值 IP_MULTICAST_TTL

    (3)设置是否允许本地回环 IP_MULTICAST_LOOP

    (4)加入多播组 IP_ADD_MEMBERSHIP

    (5)发送数据 send

    (6)接收数据 recv

    (7)退出多播组 IP_DROP_MEMBERSHIP

    mulcastserver.c

      1 #include <sys/types.h>
      2 #include <sys/socket.h>
      3 #include <arpa/inet.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <netdb.h>
      8 #include <errno.h>
      9 #define BUFLEN 255
    
     22 int main(int argc, char **argv)
     23 {
     24     struct sockaddr_in peeraddr;
     25     struct in_addr ia;
     26     int sockfd;
     27     char recmsg[BUFLEN + 1];
     28     unsigned int socklen, n;
     29     struct hostent *group;
     30     struct ip_mreq mreq;
     31 /* 创建 socket 用于UDP通讯 */
     32     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
     33     if (sockfd < 0) 
     34     {
     35         printf("socket creating err in udptalk
    ");
     36         exit(1);
     37     }
     38 /* 设置要加入组播的地址 */
     39     bzero(&mreq, sizeof(struct ip_mreq));
     40     if (argv[1]) 
     41     {
     42         if ((group = gethostbyname(argv[1])) == (struct hostent *) 0)
     43         {
     44             perror("gethostbyname");
     45             exit(errno);
     46         }
     47     } 
     48     else 
     49     {
     50         printf("you should give me a group address, 224.0.0.0-239.255.255.255
    ");
     51         exit(errno);
     52     }
     53     
     54     bcopy((void *) group->h_addr, (void *) &ia, group->h_length);
     55 /* 设置组地址 */
     56     bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr));
     57 /* 设置发送组播消息的源主机的地址信息 */
     58     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
     59 /* 把本机加入组播地址,即本机网卡作为组播成员,只有加入组才能收到组播消息 */
     60     if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(struct ip_mreq)) == -1) 
     61     {
     62         perror("setsockopt");
     63         exit(-1);
     64     }
     65     
     66     socklen = sizeof(struct sockaddr_in);
     67     memset(&peeraddr, 0, socklen);
     68     peeraddr.sin_family = AF_INET;
     69     
     70     if (argv[2])
     71     {
     72         peeraddr.sin_port = htons(atoi(argv[2]));
     73     }
     74     else
     75     {
     76         peeraddr.sin_port = htons(7838);
     77     }
     78     
     79     if (argv[1]) 
     80     {
     81         if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) 
     82         {
     83             printf("Wrong dest IP address!
    ");
     84             exit(0);
     85         }
     86     } 
     87     else 
     88     {
     89         printf("no group address given, 224.0.0.0-239.255.255.255
    ");
     90         exit(errno);
     91     }
     92 /* 绑定自己的端口和IP信息到socket上 */
     93     if (bind(sockfd, (struct sockaddr *) &peeraddr,sizeof(struct sockaddr_in)) == -1) 
     94     {
     95         printf("Bind error
    ");
     96         exit(0);
     97     }
     98 /* 循环接收网络上来的组播消息 */
     99 for (;;) 
    100 {
    101     printf("before recvfrom!
    ");
    102     bzero(recmsg, BUFLEN + 1);
    103     n = recvfrom(sockfd, recmsg, BUFLEN, 0,(struct sockaddr *) &peeraddr, &socklen);
    104     if (n < 0) 
    105     {
    106         printf("recvfrom err in udptalk!
    ");
    107         exit(4);
    108     } 
    109     else 
    110     {
    111         /* 成功接收到数据报 */
    112         recmsg[n] = 0;
    113         printf("server peer:%s
    ", recmsg);
    114     }
    115 }
    116 }

    mulcastclient.c

      1 #include <sys/types.h>
      2 #include <sys/socket.h>
      3 #include <arpa/inet.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #define BUFLEN 255
    
     20 int main(int argc, char **argv)
     21 {
     22     struct sockaddr_in peeraddr, myaddr;
     23     int sockfd;
     24     char recmsg[BUFLEN + 1];
     25     unsigned int socklen;
     26 /* 创建 socket 用于UDP通讯 */
     27     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
     28     if (sockfd < 0) 
     29     {
     30         printf("socket creating error
    ");
     31         exit(1);    
     32     }
     33     socklen = sizeof(struct sockaddr_in);
     34 /* 设置对方的端口和IP信息 */
     35     memset(&peeraddr, 0, socklen);
     36     peeraddr.sin_family = AF_INET;
     37     if (argv[2])
     38     {
     39         peeraddr.sin_port = htons(atoi(argv[2]));
     40     }
     41     else
     42     {
     43         peeraddr.sin_port = htons(7838);
     44     }
     45     
     46     if (argv[1]) 
     47     {
     48     /* 注意这里设置的对方地址是指组播地址,而不是对方的实际IP地址 */
     49         if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) 
     50         {
     51             printf("wrong group address!
    ");
     52             exit(0);
     53         }
     54     }
     55      else 
     56     {
     57         printf("no group address!
    ");
     58         exit(0);
     59     }
     60     
     61 /* 设置自己的端口和IP信息 */
     62     memset(&myaddr, 0, socklen);
     63     myaddr.sin_family = AF_INET;
     64     if (argv[4])
     65     {
     66         myaddr.sin_port = htons(atoi(argv[4]));
     67     }
     68     else
     69     {
     70         myaddr.sin_port = htons(23456);
     71     }
     72     
     73     if (argv[3]) 
     74     {
     75         if (inet_pton(AF_INET, argv[3], &myaddr.sin_addr) <= 0)
     76         {
     77             printf("self ip address error!
    ");
     78             exit(0);
     79         }
     80     } 
     81     else
     82     {
     83         myaddr.sin_addr.s_addr = INADDR_ANY;
     84     }
     85     
     86 /* 绑定自己的端口和IP信息到socket上 */
     87     if (bind(sockfd, (struct sockaddr *) &myaddr,sizeof(struct sockaddr_in)) == -1)
     88     {
     89         printf("Bind error
    ");
     90         exit(0);
     91     }
     92 /* 循环接受用户输入的消息发送组播消息 */
     93     for (;;) 
     94     {
     95         /* 接受用户输入 */
     96         bzero(recmsg, BUFLEN + 1);
     97         if (fgets(recmsg, BUFLEN, stdin) == (char *) EOF)
     98         {
     99             exit(0);
    100         }
    101         /* 发送消息 */
    102         if (sendto(sockfd, recmsg, strlen(recmsg), 0,(struct sockaddr *) &peeraddr,sizeof(struct sockaddr_in)) < 0)
    103         {
    104             printf("sendto error!
    ");
    105             exit(3);
    106         }
    107     
    108         printf("client:'%s'send ok
    ", recmsg);
    109     }
    110 }
  • 相关阅读:
    【干货分享】C# 实体类生成工具
    ASP.NET Core部署系列二:发布到CentOS上
    ASP.NET Core部署系列一:发布到IIS上
    微信公众号开发:用户管理
    微信公众号开发:自定义菜单
    像使用SQL一样对List对象集合进行排序
    使用JRebel插件实现SpringBoot应用代码热加载
    Java Stream函数式编程图文详解(二):管道数据处理
    SpringBoot生命周期管理之停掉应用服务几种方法
    本月16日SpringBoot2.2发布,有哪些变化先知晓
  • 原文地址:https://www.cnblogs.com/black-mamba/p/3751681.html
Copyright © 2011-2022 走看看