UNP卷1:第二十章(广播)

1. 单播和广播的比较

UDP数据报单播示例:

1. 通过ARP将IP地址转换为目的以太网地址:00:0a:95:79:bc:b4

2. 中间主机的以太网接口看到该帧后把它的目的以太网地址与自己的以太网地址(00:04:ac:17:bf:38)进行比较。既然它们不一致,该接口于是忽略这个帧。可见单播帧不会对该主机造成任何额外开销,因为忽略它们的是接口而不是主机。

3. 右侧主机的以太网接口也看到这个帧,当它比较该帧的目的以太网地址和自己的以太网地址时,会发现它们相同。该接口于是读入整个帧,读入完毕后可能产生一个硬件中断,致使相应设备驱动程序从接口内存中读取该帧。既然该帧类型为0x8000,该帧承载的分组于是被置于IP的输入队列。

    单播IP数据报仅通过目的IP地址指定的单个主机接收。子网上的其他主机都不受任何影响。


UDP数据报广播示例

1. 左侧主机发送该数据报时候发现,IP地址定向为广播地址,则将此IP映射为:ff:ff:ff:ff:ff:ff的以太网地址。这个地址使得该子网上的每一个以太网接口都接收该帧。

2. 右侧的那个主机把该UDP数据报传递给绑定端口520的应用进程。一个应用进程无需就为接收广播UDP数据报而进行任何特殊处理:它只需要创建一个UDP套接字,并把应用的端口号捆绑到其上。

3. 然而中间的那个主机没有任何应用进程绑定UDP端口520.该主机的UDP代码于是丢弃这个已收取的数据报。该主机绝不能发送一个ICMP端口不可达消息,因为这么做可能产生广播风暴,即子网上大量主机几乎同时产生一个响应,导致网络在这段时间内不可用。

4. 左侧主机的数据报也被传递给自己。


广播存在的根本问题:

    子网上未参加相应广播应用的所有主机也不得不沿着协议栈一路向上完整的处理收取的UDP广播数据报,直到该数据报历经UDP层时被丢弃为止。另外,子网上所有非IP的主机也不得不在数据链路层街搜完整的帧,然后在丢弃它。


广播实例1:

tserv.c:

#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <time.h>

#define MAXLINE 1024
#define SA struct sockaddr

int main(int argc, char **argv)
{
	struct sockaddr_in	srvaddr;
	int		sockfd, on = 1;
	int		num, i;
	time_t	ticks;
	char	mesg[MAXLINE + 1];

	if (argc != 3){
		printf("usage:%s<ip address><port>\n", argv[0]);
		exit(0);
	}

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(int));
	bzero(&srvaddr, sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;
	if (inet_pton(AF_INET, argv[1], &srvaddr.sin_addr) <= 0){
		printf("wrong dest ip address\n");
		exit(0);
	}
	srvaddr.sin_port = htons(atoi(argv[2]));
	for ( ; ; ){
		ticks = time(NULL);
		snprintf(mesg, sizeof(mesg), "%.24s\r\n", ctime(&ticks));
		sendto(sockfd, mesg, strlen(mesg), 0, (SA *)&srvaddr, sizeof(srvaddr));
		sleep(5);
	}

	return 0;
}

tcli.c:

#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>

#define MAXLINE 1024
#define SA struct sockaddr

int main(int argc, char **argv)
{
	struct sockaddr_in	cliaddr;
	int		sockfd, n, opt;
	char	mesg[MAXLINE + 1];

	if (argc != 2){
		printf("usage:%s<port>\n", argv[1]);
		exit(0);
	}

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	bzero(&cliaddr, sizeof(cliaddr));
	cliaddr.sin_port = htons(atoi(argv[1]));
	cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	opt = SO_REUSEADDR;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	bind(sockfd, (SA *)&cliaddr, sizeof(cliaddr));

	n = read(sockfd, mesg, MAXLINE);
	if (n > 0){
		mesg[n] = 0;
		printf("%s\n", mesg);
	}

	return 0;
}

程序输出:

服务端:

leichaojian@ThinkPad-T430i:~$ ./tserv 192.168.0.255 9876

客户端1:

leichaojian@ThinkPad-T430i:~$ ./tcli 9876
Tue Oct 14 20:40:43 2014

客户端2:

leichaojian@ThinkPad-T430i:~$ ./tcli 9876
Tue Oct 14 20:40:53 2014


广播实例2:

bcastsrv.c:

#include <sys/socket.h>
#include <signal.h>
#include <stdio.h>
#include <netinet/in.h>
#include <time.h>
#include <errno.h>

extern int errno;
#define MAXLINE 1024
#define SA struct sockaddr

static void recvfrom_alarm(int signo);
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen);

int main(int argc, char **argv)
{
	struct sockaddr_in		srvaddr;
	int		sockfd, on = 1;
	int		n;
	char	mesg[MAXLINE + 1];

	if (argc != 3){
		printf("usage:%s<ip addr><port>\n", argv[0]);
		exit(0);
	}

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	bzero(&srvaddr,sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;
	inet_pton(AF_INET, argv[1], &srvaddr.sin_addr);
	srvaddr.sin_port = htons(atoi(argv[2]));

	dg_cli(stdin, sockfd, (SA *)&srvaddr, sizeof(srvaddr));

	return 0;
}

static void recvfrom_alarm(int signo)
{
	return;
}
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
	int		n;
	const	int on = 1;
	char	sendline[MAXLINE], recvline[MAXLINE + 1];
	socklen_t	len;
	struct sockaddr *preply_addr;

	preply_addr = malloc(servlen);

	setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

	signal(SIGALRM, recvfrom_alarm);
	while (fgets(sendline, MAXLINE, fp) != NULL){
		sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

//		alarm(3);
//		for ( ; ; ){
			len = servlen;
			n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
			if (n < 0){
				if (errno == EINTR)
					break;
				else
					printf("recvfrom error\n");
			} else{
				recvline[n] = 0;
				inet_ntop(AF_INET, &preply_addr, sendline, sizeof(sendline));
				printf("from %s:%s\n", sendline, recvline);
			}
//		}
	}

	free(preply_addr);
}

bcastcli.c:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <netinet/in.h>

#define MAXLINE 1024
#define SA struct sockaddr

int main(int argc, char **argv)
{
	struct sockaddr_in	cliaddr;
	int		sockfd, n, len;
	char	mesg[MAXLINE];
	time_t	ticks;

	if (argc != 2){
		printf("usage:%s<port>\n", argv[0]);
		exit(0);
	}

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	bzero(&cliaddr, sizeof(cliaddr));
	cliaddr.sin_port = htons(atoi(argv[1]));
	cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	cliaddr.sin_family = AF_INET;

	bind(sockfd, (SA *)&cliaddr, sizeof(cliaddr));

	for ( ; ; ){
		len = sizeof(cliaddr);
		n = recvfrom(sockfd, mesg, MAXLINE, 0, (SA *)&cliaddr, &len);
		if (n < 0){
//			sleep(5);
			continue;
		}
		mesg[n] = 0;
		printf("recv: %s\n", mesg);
		ticks = time(NULL);
		snprintf(mesg, sizeof(mesg), "%.24s", ctime(&ticks));
		sendto(sockfd, mesg, 2424, 0, (SA *)&cliaddr, len);
	}

	return 0;
}

服务端:

leichaojian@ThinkPad-T430i:~$ ./bcastsrv 192.168.0.255 9876
hello
from 16.224.187.0:Tue Oct 14 21:45:38 2014
what
from 16.224.187.0:Tue Oct 14 21:45:43 2014
ha
from 16.224.187.0:Tue Oct 14 21:45:47 2014

客户端:

leichaojian@ThinkPad-T430i:~$ ./bcastcli 9876
recv: hello

recv: what

recv: ha



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值