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 }
原文地址:https://www.cnblogs.com/black-mamba/p/3751681.html