UDP组播应用示例
组播通信应用示例,组播相较于广播是有一定区别的,他们之间的区别是,组播只能是在一组之内的主机能够接收到信息,对广播来说没那么广泛,是特定一个小组能够相互接收和传递。在对比MAC地址时,如果是目标组的话才能接收数据包,即将数据包交给OS处理处理,即IP层、否则丢弃(不接受)。
UDP组播通信代码如下:
因为涉及到组的问题,我们有两个形参,组号和自己的IP地址,接收端也需要两个形参,组号和IP地址 。
setsockopt(sockfd,IPPROTO_IP,IP_ADD_membership.&mreq,sizeof(struct ip_mreq));
发送端源代码:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#define BUFLEN 255
int main(int argc,char *argv[])
{
struct sockaddr_in peeraddr,myaddr;
int sockft;
char recmsg[BUFLEN+1];
unsigned int socklen;
sockft=socket(AF_INET,SOCK_DGRAM,0); //以UDP方式创建socket对象
if(sockft<0)
{
printf(“socket creating error\n”);
exit(EXIT_FAILURE);
}
socklen=sizeof(struct sockaddr_in);
memset(&peeraddr,0,socklen);
peeraddr.sin_family=AF_INET;
peeraddr.sin_port=htons(7838); //初始化目的端口地址
if(argv[1]) //从argv[]中读取发送的目的地址,显示是一个组播地址
{
if(inet_pton(AF_INET,argv[1],&peeraddr.sin_addr)<=0)
{
printf(“wrong group address!\n”);
exit(EXIT_FAILURE);
}
}
else
{
printf(“nogroup address!\n”);
exit(EXIT_FAILURE);
}
memset(&myaddr,0,socklen);
myaddr.sin_family=AF_INET;
myaddr.sin_port=htons(23456); //绑定本机端口
if(argv[2]) //获取本机绑定IP地址,既本机IP地址
{
if(inet_pton(AF_INET,argv[2],&myaddr.sin_addr)<=0)
{
printf(“self ip address error!\n”);
exit(EXIT_FAILURE);
}
}
else
myaddr.sin_addr.s_addr=INADDR_ANY;
if(bind(sockft,(struct sockaddr )&myaddr,sizeof(struct sockaddr_in))-1) //绑定本机ip地址
{
printf(“Bind error!\n”);
exit(EXIT_FAILURE);
}
for(;????
{
bzero(recmsg,BUFLEN+1);
printf(“input message to send:”);
if(fgets(recmsg,BUFLEN,stdin)(char)EOF) //从键盘中读取一行字符
exit(EXIT_FAILURE);
if(sendto(sockft,recmsg,strlen(recmsg),0,(struct sockaddr *)&peeraddr,sizeof(struct sockaddr_in))<0)
{
printf(“sendto error!\n”);
exit(EXIT_FAILURE);
}
printf(“send message:%s”,recmsg);
}
}
接收端源代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<math.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<time.h>
#include<dirent.h>
#include<sys/errno.h>
#include<sys/wait.h>
#include<signal.h>
#include<sys/param.h>
#include<sys/syslog.h>
#include<limits.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/sem.h>
#include<errno.h>
#include<sys/shm.h>
#include<pthread.h>
#include<sys/syscall.h>
#include<semaphore.h>
#include<bits/pthreadtypes.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<netdb.h>
#define BUFLEN 255
int main(int argc,char *argv[])
{
struct sockaddr_in peeraddr;
struct in_addr ia;
int sockft;
char recmsg[BUFLEN+1];
unsigned int socklen,n;
struct hostent *group;
struct ip_mreq mreq;
if((sockft=socket(AF_INET,SOCK_DGRAM,0))<0)
{
printf(“socket creating err in udptalk\n”);
exit(EXIT_FAILURE);
}
bzero(&mreq,sizeof(struct ip_mreq));
if(argv[1])
{
if((group=gethostbyname(argv[1]))(struct hostent *)0)
{
perror(“gethostbyname”);
exit(EXIT_FAILURE);
}
}
else
{
printf(“you should give me a group address,24.0.0.0-239.255.255.255\n”);
exit(EXIT_FAILURE);
}
bcopy((void *)group->h_addr,(void *)&ia,group->h_length);
bcopy(&ia,&mreq.imr_multiaddr.s_addr,sizeof(struct in_addr));
//mreq.imr_interface.s_addr=htonl(INADDR_ANY);
//此句在某些平台将出现setsockopt设置失败,返回无此地址错误
if(argv[2])
{
if(inet_pton(AF_INET,argv[2],&mreq.imr_interface.s_addr)<=0)
{
printf(“Wrong dest IP address!\n”);
exit(EXIT_FAILURE);
}
}
//设置客户端可接收组播消息,加入到组
if(setsockopt(sockft,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(struct ip_mreq))-1)
{
perror(“setsockopt”);
exit(EXIT_FAILURE);
}
socklen=sizeof(struct sockaddr_in);
peeraddr.sin_family=AF_INET;
peeraddr.sin_port=htons(7838);
if(argv[2])
{ //
if(inet_pton(AF_INET,argv[2],&peeraddr.sin_addr)<=0)
{
printf(“Wromg dest IP address!\n”);
exit(EXIT_FAILURE);
}
}
else
{
printf(“no group address given,224.0.0.0-39.255.255.255\n”);
exit(EXIT_FAILURE);
}
if(bind(sockft,(struct sockaddr )&peeraddr,sizeof(struct sockaddr_in))==-1)
{
printf(“Bind error\n”);
exit(EXIT_FAILURE);
}
for(;????
{
bzero(recmsg,BUFLEN+1);
n=recvfrom(sockft,recmsg,BUFLEN,0,(struct sockaddr)&peeraddr,&socklen); //接收组播消息
if(n<0)
{
printf(“recvfrom err in udptalk!\n”);
exit(EXIT_FAILURE);
}
else
{
recmsg[n]=0;
printf(“peer:%s”,recmsg); //输出消息
}
}
return 0;
}
组播与广播很相似,不同的在于多了组播地址,在接受端中需要设置组播接口,使得接收端能够接收到组播信息
接收端先运行,需要组号,当组号和发送端的目的组一致时可接受到数据。
执行发送端,发送hello i’m here,然后打印所发送的数据,再一次循环,等待新的输入。
接收端接收到信息,并再一次循环以阻塞的方式等下一个数据。这是在两个不同的主机中实现的组播通信。在发送端我们给定了组号的范围提示,但输入的组号不在该范围内会提醒,然后结束本次程序的运行,否则直接认为不是该组的成员。
在某一主机中执行接收端时有可能会因为没有网卡而出现setsockopt: No such device 错误,这时你需要添加显卡,route add -net 224.0.0.0 netmask 224.0.0.0 eth0 (or similar),eth0需要结合自己主机的IP地址来唯一的确认,如果不行可以使用sudo route add -net 224.0.0.0 netmask 224.0.0.0 eth0 (or similar)来解决。