分享

Linux网络编程之多播

 紫火神兵 2014-12-05

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值

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地址
}

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


注意: TCP协议也不能用于多播.


4. 多播实例

服务器端不停的向加入多播组的主机发送数据.

服务器:

#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>

/**
广播与多播只支持UDP协议,因为TCP协议是端到端,这与广播与多播的理念相冲突
广播是局域网中一个主机对所有主机的数据通信,而多播是一个主机对一组特定的主机进行通信.多播可以是因特网,而广播只能是局域网。多播常用于视频电话,网上会议等。
setsockopt设置套接字选项可以设置多播的一些相关信息
IP_MULTICAST_TTL //设置多播的跳数值
IP_ADD_MEMBERSHIP //将主机的指定接口加入多播组,以后就从这个指定的接口发送与接收数据
IP_DROP_MEMBERSHIP //主机退出多播组
IP_MULTICAST_IF //获取默认的接口或设置多播接口
IP_MULTICAST_LOOP //设置或禁止多播数据回送,即多播的数据是否回送到本地回环接口
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));//离开组播组

组播程序的设计流程:
(1)建立socket
(2)设置跳数TTL
(3)设置是否允许本地回环
(4)加入组播组
(5)发送数据
(6)接收数据
(7)离开多播组
(8)关闭套接字
**/

//服务器实现向多播组发送数据
#define MCAST_PORT 8888
#define MCAST_ADDR "224.0.0.88"
int main(int argc,char*argv[]){
 int ret;
 int s;
 int i=1;
 struct sockaddr_in Multi_addr;//多播地址
 struct sockaddr_in client_addr;
 s=socket(AF_INET,SOCK_DGRAM,0);//建立数据报套接字
 if(s<0){
   perror("socket error");
   return -1;
 }
 Multi_addr.sin_family=AF_INET;
 Multi_addr.sin_port=htons(MCAST_PORT);//多播端口
 Multi_addr.sin_addr.s_addr=inet_addr(MCAST_ADDR);//多播地址
//向多播组发送数据
char buffer[1024];
 for(;;){
  memset(buffer,0,sizeof(buffer));
  sprintf(buffer,"%d",i);
  int size=sendto(s,buffer,strlen(buffer),0,(struct sockaddr*)&Multi_addr,sizeof(Multi_addr));
  if(size<0){
    perror("sendto error");
  }
  sleep(1);
  i++;
  memset(buffer,0,sizeof(buffer));
  int len=sizeof(client_addr);
  size=recvfrom(s,buffer,1024,0,(struct sockaddr*)&client_addr,&len);
  write(1,buffer,size);
}
close(s);
}

加入多播组的主机:

#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
//多播的客户端程序
#define PORT 8888
#define MCAST "224.0.0.88"
int main(int argc,char*argv[]){
  int s;
  int ret;
  int size;
  int ttl=10;//如果转发的次数等于10,则不再转发
  int loop=0;
  int times=0;
  char buffer[1024];
  struct sockaddr_in localaddr,fromaddr;//多播地址结构
 //建立套接字
  s=socket(AF_INET,SOCK_DGRAM,0);
  if(s<0){
   perror("socket error");
    return -1;
  }
  //多播的地址结构
  localaddr.sin_family=AF_INET;
  localaddr.sin_port=htons(PORT);//多播端口号
  localaddr.sin_addr.s_addr=htonl(INADDR_ANY);//接收任意地址发送的数据
 //绑定地址结构到套接字
 ret=bind(s,(struct sockaddr*)&localaddr,sizeof(localaddr));//客户端需要绑定端口,用来接收服务器的数据,得指定接收端口,因为数据先从服务器发送过来的
if(ret<0){
  perror("bind error");
  return -1;
}
 //设置多播的TTL值
 if(setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl))<0){
    perror("IP_MULTICAST_TTL");
    return -1;
  }

//设置数据是否发送到本地回环接口
if(setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop))<0){
  perror("IP_MULTICAST_LOOP");
  return -1;
 }
//客户端加入多播组
 struct ip_mreq mreq;
 mreq.imr_multiaddr.s_addr=inet_addr(MCAST);//多播组的IP
 mreq.imr_interface.s_addr=htonl(INADDR_ANY);//本机的默认接口IP
if(setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){
  perror("IP_ADD_MEMBERSHIP");
  return -1;
}
//循环接收多播组的消息,5次退出
for(times=0;times<20;times++){
  int len=sizeof(fromaddr);
  memset(buffer,0,sizeof(buffer));
  size=recvfrom(s,buffer,1024,0,(struct sockaddr*)&fromaddr,&len);
 if(size<0){
   perror("recvfrom ");
  return -1;
 }
 printf("receive message:%s\n",buffer);
 printf("Port is:%d\n",fromaddr.sin_port);
 size=sendto(s,"OK",2,0,(struct sockaddr*)&fromaddr,sizeof(fromaddr));//向服务器发送数据,向服务器指定的IP与端口发送数据
}

//离开多播组
ret=setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));
if(ret<0){
  perror("IP_DROP_MEMBERSHIP");
  return -1;
}
close(s);
return 0;

}


说明:设置主机的TTL值,是否允许本地回环,加入多播组,然后服务器向加入多播组的主机发送数据,主机接收数据,并响应服务器。


总结: 本文主要介绍了多播的概念,多播程序的设计流程,最后给了一个多播的实例.






    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多