前言
继续补上我的博客,这几天专注把【UNIX网络编程】的内容总结。
1.单播与广播的比较
单播 过程:
中间主机的以太网接口看到该帧,并将它的目的以太网与自己的以太网地址进行比较。由于二者不相等,接口便忽略该帧。因此,单播帧不会对这台主机造成任何额外开销,因为忽略它们的是接口而不是主机。
右边主机的以太网接口也看到该帧。并将它的目的以太网与自己的以太网地址进行比较。发现二者相等,接口便读入该帧。
广播过程:
左边的主机发送的是广播数据报,其地址为128.7.6.255,当左边的主机发送数据报时,它注意到目的IP地址是子网广播地址,于是便将它映射成48位的以太网地址:ff.ff.ff.ff.ff.ff。这使得子网上的每一个以太网接口都会接收该帧。
由于是广播类型的数据报,右侧的两台主机都将数据报传递到IP层。但是由于中间的主机没有任何应用进程绑定相应的UDP端口,于是主机的UDP代码丢弃这个已收到的数据报。
以上的例子表明了广播存在一个根本问题:子网上所有未参与广播应用系统的主机也必须完成对数据报的协议处理,直至在UDP层将它丢弃。因此以高速率产生IP数据报的应用系统(例如音频、视频应用程序)会严重影响子网上其他主机的运行,而这类型的应用程序应该采用多播技术来解决该问题。
20.4中的例子
图20-5中使用广播技术的回射客户程序,使用广播地址把输入的字符串发送给子网里所有的主机,设置了broadcast选项。
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));不过在我自己的主机上运行时发现,不设置此项同样可以运行,这一点应该和各个内核实现有关,为了有更加优良的移植性,最好还是加上这一段代码。
2.竞争状态
什么是竞争状态:
此处所说的竞争状态主要是针对UNIX系统中的信号来说的,在系统运行的过程中,如果某个函数调用会阻塞,并且打算使用UNIX信号(比如SIGALRM定时)来中断这个调用,那么就有可能遇上别的函数调用的时候,这个信号产生了,没能成功的在阻塞函数调用时候中断。这就是竞争状态。
在UNP书中,这里是希望使用SIGALRM信号来中断阻塞的recvfrom调用,但是由于未考虑如果SIGALRM信号产生时未能中断recvfrom函数的情况,因此可能会一直阻塞在recvfrom函数中。
解决方法:
1. 使用片pselect阻塞和解阻塞信号
做法是:
a.调用
sigprocmask(SIG_BLOCK, &sigset_alrm, NULL);b.调研pselect函数,该函数在阻塞阶段将保存之前的信号掩码,并设置成现在的掩码
pselect(sockfd+1, &rset, NULL, NULL, NULL, &segset_empty);c. 在pseelect阻塞时,信号是可以递交的,但单pselect返回了之后,又会恢复到之前阻塞信号的掩码,因此,此时信号是不可以中断函数调用的。
2.使用sigsetjmp和siglongjmp
siglongjmp可以从一个函数转跳到另一个函数中,称为“非局部转跳”
a.先调用sigsetjmp建立转跳缓冲区然后返回0
if( sigsetjmp(jmpbuf, 1) !=0)
<span style="white-space:pre"> </span>break;在信号来临时,在中断函数里调用siglongjmp
siglongjmp(sigbuf, 1);这样会导致上面的sigsetjmp函数返回1.然后调用break;
3.使用IPC(Inter-Process Communication,进程间通信 方式
a.建立一个管道
<span style="white-space:pre"> </span>int pipefd[2]; <span style="white-space:pre"> </span>pipe(pipefd);b.使用select测试套接字和管道
<span style="white-space:pre"> </span>FD_SET(sockfd, &rset); <span style="white-space:pre"> </span>FD_SET(pipefd[0], &rset); <span style="white-space:pre"> </span>select(maxfdp1, &rset, NULL, NULL, NULL);c.在中断函数中网管道中写入一个字,因此pipefd将会变成可读,避免了竞争。
总结
竞争问题的产生还是由于使用了UNIX信号,想让信号中断在理想的地方时很难的,因此只能使用通知主进程的方式。
所以IPC方法和select阻塞,我觉得是最方便且合适的方法。