《第10章广播与多播编程》由会员分享,可在线阅读,更多相关《第10章广播与多播编程(20页珍藏版)》请在金锄头文库上搜索。
1、第10章 广播与多播编程广播一个IP地址由网络号和主机号组成。所有主机号部分为全1的IP地址是广播地址。发送应用进程UDPIPv4数据链路UDPIPv4数据链路数据链路IPv4UDP接收应用进程以太网头部IPv4头部UDP头部UDP数据子网128.7.6目的以太网=ff:ff:ff:ff:ff:ff帧类型=0800目的IP=128.7.6.255协议=UDP目的端口=520Sendto 目的IP=128.7.6.255 目的端口=520丢弃协议=UDP帧类型0800128.7.6.99=单播128.7.6.255=广播128.7.6.5=单播128.7.6.255=广播协议=UDP端口=520
2、广播的实现应用程序只能通过应用程序只能通过UDP方式发送广播。方式发送广播。一般情况下,如果调用一般情况下,如果调用sendto,只能向非广播,只能向非广播地址发送数据报。如果要发送广播数据报,必地址发送数据报。如果要发送广播数据报,必须告诉内核,可以通过设置须告诉内核,可以通过设置SO_BROADCAST套接口选项来做到这一点。套接口选项来做到这一点。int on=1;setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(int);广播实例服务端为tserv.c,运行时需指定广播地址和端口号,运行后每3秒发送一次广播,将本机时间通知本子网内
3、所有主机。服务器端程序服务器端程序tserv.c#include #include #include #include #define BUFLEN 255void getcurtime(char *curtime) time_t tm; time(&tm); snprintf(curtime,BUFLEN,%sn,ctime(&tm);int main(int argc,char *argv) struct sockaddr_in peeraddr;int sockfd,on=1;int num,i;char msgBUFLEN+1;if(argc!=3) printf(usage:%sn,
4、argv0); exit(0); sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd0) fprintf(stderr,socket creating error in ); exit(1);setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(int);memset(&peeraddr,0,sizeof(struct sockaddr_in);peeraddr.sin_family=AF_INET;if(inet_pton(AF_INET,argv1,&peeraddr.sin_addr)=0) p
5、rintf(Wrong dest IP addressn); exit(0);peeraddr.sin_port=htons(atoi(argv2);for(;)getcurtime(msg);int a;a=sendto(sockfd,msg,strlen(msg),0,(struct sockaddr *)&peeraddr,sizeof(struct sockaddr_in);printf(%d,a);fflush(stdout);sleep(3);客户端程序客户端程序 tcli.c (只需侦听某一固定端口的数据报只需侦听某一固定端口的数据报,接收一个数据报就返回。接收一个数据报就返回。
6、)#include #include #include #include #define BUFLEN 255int main(int argc,char* argv) struct sockaddr_in localaddr; int sockfd,n; char msgBUFLEN+1; if(argc!=2) printf(usage:%sn,argv0); exit(0); sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd0) fprintf(stderr,socket creating error in ); exit(1);memset(&
7、localaddr,0,sizeof(struct sockaddr_in);localaddr.sin_port=htons(atoi(argv1);localaddr.sin_addr.s_addr=htonl(INADDR_ANY);int opt = SO_REUSEADDR;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt);if(bind(sockfd,(struct sockaddr *)&localaddr,sizeof(struct sockaddr_in)0) fprintf(stderr,bind
8、error in );exit(2); n=read(sockfd,msg,BUFLEN);if(n=-1) fprintf(stderr,read error in ); exit(3);else msgn=0; printf(%s,msg);程序运行结果程序运行结果如果在服务器端输入./serv 222.18.113.171 1234则两个客户不会同时收到数据报。多播多播是通过D类地址进行的,D类地址的前4位为1110,后面28位为群播的组标识。地址范围224.0.0.0 到239.255.255.255特殊的IPv4多播地址:224.0.0.0 保留224.0.0.1 本子网上所有主机2
9、24.0.0.2 本子网上所有网关224.0.1.1 NTP(网络时间协议)组多播的原理当一个多播分组到达一个以太网时,形成帧后它的当一个多播分组到达一个以太网时,形成帧后它的MAC地地址为址为01:00:5e:xx:xx:xx,其后,其后23位由多播组标识的位由多播组标识的后后23位映射而成。例如目的地址为位映射而成。例如目的地址为224.0.1.1的多播分的多播分组,在以太网上帧的组,在以太网上帧的MAC地址就为地址就为01:00:5e:00:01:01,如下图示。,如下图示。111000000000000000000001000000010000000100000000010111100
10、00000000000000100000001IP地址MAC地址由于多播IP地址中组标识有28位,而映射到MAC地址的只有23位,还差5位,所以有32个组将映射成相同的MAC地址,例如224.0.0.1,225.0.1.1,239.128.1.1都映射到MAC地址01:00:5e:00:01:01。因此要由IP层来检验到达的多播分组是否是自已所加入的多播组。如果不是,则抛弃该分组。应用程序应用程序UDPIP层层132.0.0.100数据链路层数据链路层52:37:4a:6d:7f:5e应用程序应用程序UDPIP层层132.0.0.129应用程序应用程序UDPIP层层132.0.0.168数据链
11、路层数据链路层52:23:4e:6f:2c:35数据链路层数据链路层00:2e:2c:5f:ae:3f发送数据报IP:224.0.1.1端口1234通过ARP解析224.0.1.1对应01:00:5e:00:01:01接收数据报端口1234应用程序指定132.0.0.129加入多播组224.0.1.1IP层指示接收MAC地址为01:00:5e:00:01:01的帧加入225.0.1.1丢弃多播数据报在子网中的发送接收多播的实现 应用程序只需向多播组地址发送数据报,接收应用应用程序只需向多播组地址发送数据报,接收应用程序加入这个多播组。在指定端口上进行侦听。程序加入这个多播组。在指定端口上进行侦
12、听。 加入多播组的方法是设置套接口选项加入多播组的方法是设置套接口选项IP_ADD_MEMBERSHIP.它要用它要用要如下结构:要如下结构:Struct ip_mreq struct in_addr imr_multiaddr; /*IPv4的的D类多播地址类多播地址*/Struct in_addr imr_interface; /*本地接口本地接口IPv4地址地址*/;例:例:setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mcaddr,sizeof(struct ip_mreq)多播的实现服务器端程序没有什么改变,只要将设置socket选项
13、SO_BROADCAST的那行去掉就可以了。客户程序源码如下页:源程序源程序mtcli.c#include #include #include #include #define BUFLEN 255int main(int argc,char* argv) struct sockaddr_in localaddr; int sockfd,n; struct ip_mreq mcaddr; char msgBUFLEN+1; if(argc3) printf(usage:%sn,argv0); exit(0); sockfd=socket(AF_INET,SOCK_DGRAM,0);if(soc
14、kfd0) fprintf(stderr,socket creating error in ); exit(1);memset(&localaddr,0,sizeof(struct sockaddr_in);localaddr.sin_port=htons(atoi(argv2);localaddr.sin_addr.s_addr=htonl(INADDR_ANY);if(inet_pton(AF_INET,222.18.113.171,&mcaddr.imr_interface)=0)perror(failure);exit(0);if(inet_pton(AF_INET,argv1,&mc
15、addr.imr_multiaddr)=0) printf(Wrong multicast IP addressn); exit(0);printf(ip:%s,inet_ntoa(mcaddr.imr_multiaddr);fflush(stdout);if(setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mcaddr,sizeof(struct ip_mreq)0)perror(setsockopt error in mtcli.c,join multicast failedn); exit(4);if(bind(sockfd,(struct sockaddr *)&localaddr,sizeof(struct sockaddr_in)0) fprintf(stderr,bind error in );exit(2); n=read(sockfd,msg,BUFLEN);if(n=-1) fprintf(stderr,read error in ); exit(3);else msgn=0; printf(%s,msg);程序运行结果向多播组224.0.4.5发送数据报加入224.0.4.5并在1234端口侦听思考:客户收到数据报的源地址是多少?