UNP卷一chapter20 广播
1、单播、广播及多播等不同寻址方式
类型 | IPv4 | IPv6 | TCP | UDP | 所标识接口数 | 递送到接口数 |
单播 | Y | Y | Y | Y | 一个 | 一个 |
任播 | * | Y | 尚没有 | Y | 一组 | 一组中的一个 |
多播 | 可选 | Y | Y | 一组 | 一组中的全体 | |
广播 | Y | Y | 全体 | 全体 |
表中要点:
i、多播支持在IPv4中是可选的,在IPv6中却是必需的
ii、IPv6不支持广播。使用广播的任何IPv4应用程序一旦移植到IPv6就必须改用多播重新新编写
iii、广播和多播要求用于UDP或原始IP,不能用于TCP
广播的用途有:资源发现,多个客户主机与单个服务器主机通信的局域网环境中尽量减少分组流通。如下,
ARP:在子网中广播一个请求说“IP地址为a.b.c.d的系统亮明身份,请告诉我你的硬件地址”。ARP使用链路层广播而不是IP层广播。
DHCP:在子网有DHCP服务器下,DHCP客户主机向子网发送广播地址以请求获取自己的IP地址、子网掩码以及本子网的受限广播地址。
还有NTP、路由守护进程等等运用广播的例子。
2、广播地址
i、子网定向广播地址:{子网ID,-1}(此为IPv4地址表示方法,子网ID表示由子网掩码覆盖的连续位,主机ID表示以外的位,-1表示所有位均为1的字段)
ii、受限广播地址:{-1,-1}或255.255.255.255。路由器从不转发目的地址为255.255.255.255的IP数据报。
3、UDP数据报广播示例
目的IP地址是所在以太网的子网定向广播地址,于是把它映射成48位全为1的以太网地址:ff:ff:ff:ff:ff:ff。这个地址使得该子网上的每一个以太网接口都接收该帧。
右侧主机把该UDP数据报传递给绑定端口520的应用进程。一个应用进程无需就为接收广播UDP数据报而进行任何特殊处理:它只需要创建一个UDP套接字,并把应用的端口号摁绑到其上。(假设捆绑的IP地址是典型的INADDR_ANY。)
中间的主机没有任何应用进程绑定的UDP端口520。于是该主机UDP代码丢弃这个已收取的数据报。切记,该主机绝不能发送一个ICMP端口不可达消息,因为这么做可能产生广播风暴,导致网络拥塞。
4、竞争状态(当有多个进程访问共享的数据,而正确结果取决于进程的执行顺序)
三种方法解决在使用广播的dg_cli函数中竞争状态问题。
i、用pselect阻塞和解阻塞信号(需要了解pselect的用法,见书上6.9节P142)
#include "unp.h"static void recvfrom_alarm(int);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];fd_set rset;sigset_t sigset_alrm, sigset_empty;//生成两个信号集socklen_t len;struct sockaddr *preply_addr;preply_addr = Malloc(servlen);Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));//开启套接字广播选项FD_ZERO(&rset);Sigemptyset(&sigset_empty);//声明信号集,初始化为空集Sigemptyset(&sigset_alrm);//声明信号集,初始化为空集Sigaddset(&sigset_alrm, SIGALRM);//再在信号集sigset_alarm,打开与SIGALRM对应的位Signal(SIGALRM, recvfrom_alarm);while (Fgets(sendline, MAXLINE, fp) != NULL) {Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL);//调用sigprocmask函数,阻塞SIGALRM(即信号发生时,不会立即调用信号处理函数)alarm(5);for (; ; ) {FD_SET(sockfd, &rset);n = pselect(sockfd + 1, &rset, NULL, NULL, NULL, &sigset_empty);//最后一个参数表示信号集为空集,意味着在pselect调用期间if (n < 0) { //SIGALRM不阻塞,当pselect返回时,又自动将SIGALRM设置为阻塞if (errno == EINTR)break;elseerr_sys("pselect error");}else if (n != 1)err_sys("pselect error: returned %d", n);len = servlen;n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);recvline[n] = 0; /* null terminate */printf("from %s: %s",Sock_ntop_host(preply_addr, len), recvline);}}free(preply_addr);
}static void
recvfrom_alarm(int signo)
{return; /* just interrupt the recvfrom() */
}
ii、使用sigsetjump和siglongjmp
#include "unp.h"
#include <setjmp.h>static void recvfrom_alarm(int);
static sigjmp_buf jmpbuf;//分配一个将由本函数及其信号处理函数使用的跳转Buffervoid
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);//捕获SIGALRM,并执行信号处理函数recvfrom_alarmwhile (Fgets(sendline, MAXLINE, fp) != NULL) {Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);alarm(5);for (; ; ) {if (sigsetjmp(jmpbuf, 1) != 0)//建立跳转缓冲区后返回0break;len = servlen;n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);recvline[n] = 0; /* null terminate */printf("from %s: %s",Sock_ntop_host(preply_addr, len), recvline);}}free(preply_addr);
}static void
recvfrom_alarm(int signo)
{siglongjmp(jmpbuf, 1);//当SIGALRM信号被递交时,调用siglongjmp,跳转至sigsetjmp设置的缓冲区,并返回siglongjmp的第二个参数1,从而导致dg_cli的for循环结束
}
iii、使用从信号处理函数到主控函数的IPC
#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);//创建一个普通Unix管道,返回两个描述符,pipefd[0](读入),pipefd[1](写出)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;elseerr_sys("select error");}if (FD_ISSET(sockfd, &rset)) {len = servlen;n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);recvline[n] = 0; /* null terminate */printf("from %s: %s",Sock_ntop_host(preply_addr, len), recvline);}if (FD_ISSET(pipefd[0], &rset)) {Read(pipefd[0], &n, 1); /* timer expired */break;}}}free(preply_addr);
}static void
recvfrom_alarm(int signo)
{Write(pipefd[1], "", 1); /* write one null byte to pipe */return;
}
以上知识点来均来自steven先生所著UNP卷一(version3),刚开始学习网络编程,如有不正确之处请大家多多指正。
UNP卷一chapter20 广播相关推荐
- UNP卷一chapter17 ioctl操作
网络程序(特别是服务器程序)经常在程序启动执行后使用ioctl获取所在主机全部网络接口的信息,包括:接口地址.是否支持广播.是否支持多播,等等.所以此部分的ioctl及源码的学习可将其视为一个ifco ...
- TCP/IP详解卷一之广播和本地组播(IGMP和MLD)
1 引言 -广播和组播为应用程序提供了两种服务: · 数据分组交付至多个目的地: · 通过客户端请求/发现服务器,如DHCP. -广播比较简单,但开销更高:组播比较复杂,但效率更高. -IPv4支持广 ...
- gns3中两个路由器分别连接主机然后分析ip数据转发报文arp协议_TCP/IP协议知识总结...
总体 首先,展示下总体的思维导图.接下来,按照每个点解释. OSI七层模型 开放式系统互联模型(英语:Open System Interconnection Model,缩写:OSI:简称为OSI模型 ...
- 《Linux多线程服务端编程:使用muduoC++网络库》学习笔记
文章目录 第1章 线程安全的对象生命期管理 1.1 当析构函数遇到多线程 1.1.1 线程安全的定义 1.1.3 线程安全实例 1.2 对象的创建很简单 1.3 销毁很难 1.4 线程安全的Obser ...
- [综合面试] 跨专业大牛的IT求职面试经验分享以及学习知识路线图梳理
百度三面,跪了,最中意的一家公司的最后一面,结束了我的校招应聘.总结经验和教训,希望能帮助一些人. 个人背景: 本科:大连理工信管专业,本科毕业代码量<500行.中科大读研,专业是管科,学的全是 ...
- 拔掉网线时Socket的检查方法
最近在做有关于TCP采集程序时,发现在客户端与服务器通过TCP socket进行通信的时候,如果客户端应用程序正常或者异常退出时,服务器都可以在对应的socket通信连接上获得响应(如返回0,或者抛出 ...
- 如何检查Socket是否断开
如何检查Socket是否断开 分类: 网络编程 2011-08-16 14:07 3392人阅读 评论(0) 收藏 举报 socketSocketSOCKET 最近在做一个TCP采集程序,使用到C/ ...
- 如何通过自学找到一份开发的工作?
01 学习过程 比较仔细的学习了<c++primer>,并对每个习题都自己写代码实现了一遍,包括稍微复杂一点的例子. 认真读完了<effective c++>,<effe ...
- python如何判断tcp异常断开_TCP socket如何判断连接断开
http://blog.csdn.net/zzhongcy/article/details/21992123 SO_KEEPALIVE是系统底层的机制,用于系统维护每一个tcp连接的. 心跳线程属于应 ...
最新文章
- Error: unterminated string literal。通常原因是输出字符str中包含换行符导致的。
- python入门自学-你是如何自学 Python 的?
- Facebook表示将认真对待平台上严重的服装虚假广告问题
- GMGridView cell button
- 从0到1,你的导流姿势真的正确吗?
- 手写简版spring --4--注入属性和依赖对象
- java集群_身为Java程序员的你知道分布式与集群的联系及区别吗?
- oracle报错ora-00200,oracle 11gR2 rac 创建database报ORA-00200错误
- 【Vue2.0】— 插件(十六)
- mysql in 文本_MySQL_mysql 的load data infile,LOAD DATA INFILE语句从一个文本文 - phpStudy...
- qt 隐藏控制台_带可选GUI的Qt控制台应用程序
- 数据之路 - 数据可视化 - PowerBI工具
- 你缺的不是时间而是专注力
- Atmega128 AVR Studio熔丝位(Fuse)设置
- c 语言奇数幻方代码,【C】——幻方算法(示例代码)
- CDH集群执行任务报错:User xxx not found
- 企业的组织架构对技术架构的影响
- 红宝书读书笔记 第八章
- vs开发,添加try catch(...)发现没有捕获异常,需要对编译命令进行设置
- 博途中WinCC VBS 脚本的基础用法