UNP学习 广播
Posted 思而不学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UNP学习 广播相关的知识,希望对你有一定的参考价值。
一、概述
虽然UDP支持各种形式的地址,但TCP只支持单播地址。
上图要点是:
- IPv4对多播的支持是可选的,而IPv6则时必须的。
- IPv6没有提供对广播的支持:当使用广播的IPv4应用程序一直到IPv6时,必须使用IPv6的多播方式进行重新编码。
- 广播和多播要使用UDP,二者都不能使用TCP
广播的用途:
1.假定服务器主机在本地子网上,但不知道它的单播IP地址时,对它进行定位,这就是资源发现。
2.当有多个客户和单个服务器通信时,减少局域网上数据流量。
常见的实例
1.ARP:ARP是IPv4的一个i额基本组成部分,而不是一个用户应用程序。
2.BOOTP(引导协议,Bootstrap Protocol):客户假定有一台服务器主机在本地子网上。
3.NTP(网络时间协议,Network Timer Protocol):一种常见的情形是:一个NTP客户主机可能配置成使用一个或多个服务器主机IP地址,其上面的NTP客户于是以某个频率轮询这些服务器。
4.路由后台进程。
二、广播地址
如果用{netid,subnetid,hostid}({网络ID,子网ID,主机ID})表示IPv4地址,那么有四种类型的广播地址。
1.子网广播地址:{netid,subnetid,-1}。这类地址编排指定子网上的所有接口。
2.全部子网广播地址:{netid,-1,-1}。这类广播地址编排指定网络上的所有子网。
3.网络广播地址:{netid,-1}。这类地址用于不进行子网划分的网络。
4.受限广播地址:{-1,-1,-1}或255.255.255.255。路由器从不转发目的地址为255.255.255.255的IP数据报
三、竞争状态
多个进程访问共享数据,但正确结果依赖于进程的执行顺序,这种情况我们称之为竞争状态。
竞争状态通常是线程编程中时钟要注意的一个重要问题,因为在线程中有非常多的数据需要共享。
在进行信号处理时,通常会出现各种类型的竞争状态。这是因为在我们的程序执行过程中,内核随时都会递交信号。
例子1:
1 #include "unp.h" 2 static void recvfrom_alarm(int); 3 void 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) 5 { 6 int n; 7 const int on = 1; 8 char sendline[MAXLINE], recvline[MAXLINE+1]; 9 sigset_t sigset_alarm; 10 socklen_t len; 11 struct sockaddr *preply_addr; 12 preply_addr = Malloc(servlen); 13 Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); 14 Sigemptyset(&sigset_alarm); 15 Signal(SIGALRM, recvfrom_alarm); 16 while(Fgets(sendline, MAXLINE, fp) != NULL) { 17 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); 18 alarm(5); 19 for( ; ;) { 20 len = servlen; 21 Sigprocmask(SIG_UNBLOCK, &sigset_alrm, NULL); 22 n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len); 23 Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL); 24 if(n < 0) { 25 if(errno == EINTR) 26 break; /* waited long enough for replies */ 27 else 28 err_sys("recvfrom error"); 29 } else { 30 recvline[n] = 0; /* null terminate */ 31 printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline); 32 } 33 } 34 } 35 } 36 37 static void 38 recvfrom_alarm(int signo) 39 { 40 return; /* just nterrupt the recvfrom() */ 41 }
解阻塞信号、调用recvfrom和阻塞信号都是互相独立的系统调用。假定recvfrom返回了最后一个应答数据报并且SIGALRM信号在recvfrom和阻塞信号之间递交,下一次recvfrom的调用将永远阻塞。错误
例子2:
#include "unp.h" #include <setjmp.h> static void recvfrom_alarm(int); static sigjmp_buf jmpbuf; 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(5); for( ; ; ) { if(sigsetjmp(jmpbuf, 1) != 0) break; len = servlen; n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len); recvline[n] = 0; printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline); } } } static void recvfrom_alarm(int signo) { siglongjmp(jmpbuf, 1); }
pselect的关键点是设置信号掩码、测试描述字及恢复信号掩码等操作都是原子操作。错误
例子3:
#include "unp.h" static void recvfrom_alarm(int); static int pipefd[2]; void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) { int n, maxfdp1; const int on = 1; char sendline[MAXLINE], recvline[MAXLINE + 1]; fd_set rset; socklen_t len; struct sockaddr *preply_addr; preply_addr = Malloc(servlen); Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); Pipe(pipefd); maxfdp1 = max(sockfd, pipefd[0]) + 1; FD_ZERO(&rset); Signal(SIGALRM, recvfrom_alarm); while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); alarm(5); for( ; ; ) { FD_SET(sockfd, &rset); FD_SET(pipefd[0], &rset); if((n = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) { if(errno == EINTR) continue; else err_sys("select error"); } if(FD_ISSET(sockfd, &rset)) { len = servlen; n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len); recvline[n] = 0; printf("from %s: %s", Sock_ntop_host(preply_addr, len), recvline); } if(FD_ISSET(pipefd[0], &rset)) { Read(pipefd[0], &n, 1); break; } } } } static void recvfrom_alarm(int signo) { Write(pipefd[1], "", 1); return; }
另一个解决同一问题的正确方法。不是让信号处理简单的返回,期望这样能够中断被阻塞的rrecvfrom相反,我们让信号黑醋栗程序使用IPC通知dg_cli函数到抵制其到时。
以上是关于UNP学习 广播的主要内容,如果未能解决你的问题,请参考以下文章