P110解决网络编程可能会遇到的三种情况:
(1)当fork子进程时,必须捕获SIGCHLD信号;(理解:这里的捕获不是立即去捕获,而是注册捕获信号,随时在子进程发送信号的时候了,就捕获。为什么要早注册呢,是因为你不知道子进程什么时候发。)
(2)当捕获信号时,必须处理被中断的系统调用;
(3)SIGCHLD的信号处理函数必须正确编写,应使用waitpid函数以免留下僵死进程。
P120解决穿越套接字传送二进制结构的问题:
(1)把所有的数值作为文本串来传递,这样就不会引起不同格式二级制数和大小端主机的问题;
(2)显示定义所支持数据类型的二进制格式(位数、大端或小端字节序)。
P172Nagle算法
在于减少广域网上小分组的数目。该算法指出,如果某个给定连接上有待确认数据,那么原本应该作为用户写操作响应的在该连接上立即发送相应小分组的行为就不会发生,知道现有数据被确认为止。
经常与ACK算法联用:ACK算法使得TCP在接收到数据后不立即发送ACK,而是等待一段时间(50~200ms),然后才发送ACK。
有三种办法修改不适合使用上述两种算法:
(1)使用writev,writev调用最终导致调用TCP输出功能一次而不是两次,其结果是产生一个TCP分节;
(2)把前4字节的数据和后396数据复制到单个缓冲区,然后对该缓冲区调用一次write;
(3)设置TCP_NODELAY套接字选项,继续调用write两次。这是不可取的方法会损害网络。
P189UDP和TCP的区别
大多数TCP服务器是一个并发服务器,而大多数UDP服务器是迭代服务器。
udp的客户服务程序是不可靠的。如果一个客户数据包丢失,或者是客户数据包到达了但是服务器无法应答,客户将永远阻塞在recvfrom。防止这样永久阻塞的方法是给客户recvfrom设置一个超时。
P270可重入和不可重入的问题
不可重入函数会造成在不同线程间调用时,全局变量的值发生改变;
而可重入函数调用malloc分配内存容易造成内存的泄露。
P286守护进程
daemon是在后台运行且不与任何控制终端关联的进程,常源于系统初始化脚本启动。
P316避免在套接字上使用标准I/O函数库
当标准I/O流的便利性大过对缓冲带来的bug担忧时,在套接字上使用标准I/O流是可行的,但是这种情况也罕见。
P362非阻塞accept解决的问题
当采用select返回监听套接字的可读条件时,遇到一个繁忙的服务器和客户程序马上发送RST断开连接时会出现问题,使服务器程序阻塞于accept而无法处理其他已经就绪的套接字描述符。
解决的办法是:(1)当使用select获悉某个监听套接字完成连接准备被accept时,把这个监听套接字设置为非阻塞;
(2)在后续的accept调用中忽略以下错误,比如EWOULDBLOCK等。
P366和网络相关ioctl的请求
套接字请求,文件操作,接口操作,ARP高速缓存操作,路由表操作,流系统。
P425信号会在程序执行过程中由内核随时随地提交,容易阻塞在recvfrom中,解决办法是
用pselect函数阻塞解阻塞信号,它设置信号掩码,测试描述符以及恢复信号掩码这三个操作在调用进程看来是一个原子操作;
使用sigsetjmp和siglongjmp同样可以;
使用从信号处理函数到主控函数的IPC,管道通信的测试跳出for循环来防止。
P467UDP和TCP的区别,何时用UDP代替TCP
TCP是可靠的,而UDP是不可靠的;
事实上如果应用程序使用广播或多播,就必须使用UDP;
UDP没有连接的建立和拆除
对于实时音频能够通过插值弥补遗失数据,那么丢失的分节也许不必要重传,可以使用UDP;
如果两端事先协定请求和应答的大小,那么也许不需要窗口式流量控制,可以使用UDP;
对于海量数据传输不应该使用UDP。
如今良好的TCP实现能够充分发挥网络带宽容量,而且越来越多的应用程序设计愿意在UDP中再造一个TCP。
P534进程与线程调用的网络编程区别
进程fork要把父进程的内存映像复制到子进程;
父子进程之间的通信采用IPC模式;
线程为轻权进程,创建速度更快;
线程间共享全局内存,易于共享,但需要考虑同步问题。
p674客户/服务器程序设计范式
迭代服务器,无进程;
并发服务器,每个客户请求fork一个子进程;
预先派生子进程,每个子进程无保护的调用accept;
预先派生子进程,使用文件上锁保护accept;
预先派生子进程,使用线程互斥锁上锁保护accept;
预先派生子进程,父进程向子进程传递套接字描述符;
并发服务器,每个客户请求创建一个线程;
预先创建线程服务器,使用互斥锁上锁保护accept;
预先创建线程服务器,由主线程调用accept。
p674客户/服务器程序设计范式的对比
负载较轻时,选择并发服务器即可;
相比并发服务器,预先创建子进程池或者线程池更快;
让所有子进程或线程自行调用accept比单独让父进程或主线程调用accept然后传递描述符更快;
让所有子进程或线程阻塞在同一个accept比阻塞在同一个select更可取;
使用线程比进程更快,不过也取决于具体的操作系统。