linux 多播

1.概念

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

 

2. 多播套接字设置

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

IP_MULTICAST_TTL    设置多播的TTL值

IP_MULTICAST_IF      获取或设置多播接口

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

IP_ADD_MEMBERSHIP   将指定的接口加入多播

IP_DROP_MEMBERSHIP  退出多播组

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

/*PROTO_IP-选项所在的协议层
*IP_MULTICAST_TTL-选项名
*&ttl-设置的内存缓冲区
*sizeof(ttl)-设置的内存缓冲区长度*/

int ttl=255;
setsockopt(s,IPPROTO_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

 

4、多播服务器端

 1 //服务器实现向多播组发送数据
 2 #define MCAST_PORT 8888
 3 #define MCAST_ADDR "224.0.0.88"
 4 int main(int argc,char*argv[]){
 5  int ret;
 6  int s;
 7  int i=1;
 8  struct sockaddr_in Multi_addr;//多播地址
 9  struct sockaddr_in client_addr;
10  s=socket(AF_INET,SOCK_DGRAM,0);//建立数据报套接字
11  if(s<0){
12    perror("socket error");
13    return -1;
14  }
15  Multi_addr.sin_family=AF_INET;
16  Multi_addr.sin_port=htons(MCAST_PORT);//多播端口
17  Multi_addr.sin_addr.s_addr=inet_addr(MCAST_ADDR);//多播地址
18 //向多播组发送数据
19 char buffer[1024];
20  for(;;){
21   memset(buffer,0,sizeof(buffer));
22   sprintf(buffer,"%d",i);
23   int size=sendto(s,buffer,strlen(buffer),0,(struct sockaddr*)&Multi_addr,sizeof(Multi_addr));
24   if(size<0){
25     perror("sendto error");
26   }
27   sleep(1);
28   i++;
29   memset(buffer,0,sizeof(buffer));
30   int len=sizeof(client_addr);
31   size=recvfrom(s,buffer,1024,0,(struct sockaddr*)&client_addr,&len);
32   write(1,buffer,size);
33 }
34 close(s);
35 }

 

5、客户端代码

 1 加入多播组的主机:
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <string.h>
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <netinet/in.h>
 8 //多播的客户端程序
 9 #define PORT 8888
10 #define MCAST "224.0.0.88"
11 int main(int argc,char*argv[]){
12   int s;
13   int ret;
14   int size;
15   int ttl=10;//如果转发的次数等于10,则不再转发
16   int loop=0;
17   int times=0;
18   char buffer[1024];
19   struct sockaddr_in localaddr,fromaddr;//多播地址结构
20  //建立套接字
21   s=socket(AF_INET,SOCK_DGRAM,0);
22   if(s<0){
23    perror("socket error");
24     return -1;
25   }
26   //多播的地址结构
27   localaddr.sin_family=AF_INET;
28   localaddr.sin_port=htons(PORT);//多播端口号
29   localaddr.sin_addr.s_addr=htonl(INADDR_ANY);//接收任意地址发送的数据
30  //绑定地址结构到套接字
31  ret=bind(s,(struct sockaddr*)&localaddr,sizeof(localaddr));//客户端需要绑定端口,用来接收服务器的数据,得指定接收端口,因为数据先从服务器发送过来的
32 if(ret<0){
33   perror("bind error");
34   return -1;
35 }
36  //设置多播的TTL值
37  if(setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl))<0){
38     perror("IP_MULTICAST_TTL");
39     return -1;
40   }
41 
42 //设置数据是否发送到本地回环接口
43 if(setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop))<0){
44   perror("IP_MULTICAST_LOOP");
45   return -1;
46  }
47 //客户端加入多播组
48  struct ip_mreq mreq;
49  mreq.imr_multiaddr.s_addr=inet_addr(MCAST);//多播组的IP
50  mreq.imr_interface.s_addr=htonl(INADDR_ANY);//本机的默认接口IP
51 if(setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){
52   perror("IP_ADD_MEMBERSHIP");
53   return -1;
54 }
55 //循环接收多播组的消息,5次退出
56 for(times=0;times<20;times++){
57   int len=sizeof(fromaddr);
58   memset(buffer,0,sizeof(buffer));
59   size=recvfrom(s,buffer,1024,0,(struct sockaddr*)&fromaddr,&len);
60  if(size<0){
61    perror("recvfrom ");
62   return -1;
63  }
64  printf("receive message:%s\n",buffer);
65  printf("Port is:%d\n",fromaddr.sin_port);
66  size=sendto(s,"OK",2,0,(struct sockaddr*)&fromaddr,sizeof(fromaddr));//向服务器发送数据,向服务器指定的IP与端口发送数据
67 }
68 
69 //离开多播组
70 ret=setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));
71 if(ret<0){
72   perror("IP_DROP_MEMBERSHIP");
73   return -1;
74 }
75 close(s);
76 return 0;
77 
78 } 

 

posted on 2013-07-23 17:13  meizixiong  阅读(3044)  评论(0编辑  收藏  举报