UNIX网络编程 卷1:套接字联网API(第3版)源代码
-
函数
-
程序
TCP回射服务器 | v1 | 客户端 | str_cli函数(阻塞于标准输入时无法处理来自服务器子进程的FIN分节) |
服务器(多进程) | 服务器会产生僵尸子进程 | ||
v2 | 服务器(多进程) | 处理服务器僵尸子进程,会中断服务器系统调用 | |
v3 | 服务器(多进程) | 处理服务器被中断的系统调用,无法同时处理多个SIGCHLD信号 | |
v4 | 客户端 | 正常终止时引起服务器5个子进程终止 | |
服务器(多进程) | 同时处理多个SIGCHLD信号 | ||
select | 客户端 | str_cli函数(解决v1版的问题,但无法处理重定向、无法处理I/O缓冲) | |
客户端 | str_cli函数(解决前一版的问题) | ||
服务器(单进程) | 重写v4版服务器,使用单进程减少了多进程的开销 | ||
poll | 服务器(单进程) | 重写v4版服务器,使用单进程减少了多进程的开销 | |
总结 | v1-v4:正确处理服务器终止的子进程 |
UDP回射服务器 | v1 | 客户端 | dg_cli函数(v1) 问题一:任何进程可向客户端发数据,会与服务器的回射数据报混杂 问题二:客户数据报或服务器应答丢失会使客户永久阻塞于recvfrom 问题三:服务器未启动会使客户端阻塞于recvfrom |
服务器(单进程) | dg_echo函数 | ||
v2 | 客户端 | dg_cli函数(v2) 处理问题一,验证接收到的响应。但无法处理服务器多宿(多个IP)的情况 |
|
v3 | 客户端(connect版) | dg_cli函数(v3) |
|
v4 | 客户端 | dg_cli函数(v4):写2000个1400字节的UDP数据报给服务器 问题:UDP缺乏流量控制,服务器接收速率慢时,缓冲区被发送端淹没 |
|
服务器(单进程) | dg_echo函数 | ||
v5 | 服务器(单进程) | dg_echo函数(增大接收缓冲区的大小) | |
总结 | v1:问题二、三的根本原因是UDP数据传输不可靠 v4-v5:UDP缺乏流量控制,服务器接收的数据报数目不定,依赖诸多因素 |
宏值与头文件表:
常量 | 值 | 所在头文件 |
---|---|---|
SERV_PORT | 9877 | unp.h |
MAXLINE | 4096 | unp.h |
可以调用sigaction函数来检查或修改与指定信号相关联的处理动作。传入“信号处理函数”,只要有信号发生,信号处理函数就会被调用,这种行为称为“捕获信号”
/*
* 参数:
* signo:要检测或修改其具体动作的信号编号
* act:非空,则要修改其动作
* oact:非空,则经由oact返回该信号的上一个动作
*/
int sigaction(int signo,const struct sigaction *restrict act,
struct sigaction *restrict oact);
struct sigaction {
void (*sa_handler)(int); //信号处理函数的地址,或SIG_IGN、SIG_DFL
//在调用信号处理函数之前,信号集要加到进程的信号屏蔽字中。
//仅当从信号处理函数返回时再将进程的信号屏蔽字恢复为原先值。
//这样,在调用信号处理函数时就能阻塞某些信号。在信号处理程序被调用时,
//操作系统建立的新信号屏蔽字包括正被传递的信号。因此保证了在处理一个
//给定的信号时,如果这种信号再次发生,那么它会被阻塞到对前一信号的处理
//结束为止。如果一个信号在被阻塞期间产生了一次或多次,那么该信号被解
//阻塞之后通常只递交一次,也就是说UNIX信号默认是不排队的
sigset_t sa_mask; //阻塞额外的信号
int sa_flags; //信号标志
void (*sa_sigaction)(int,siginfo_t *,void *);
}
//信号处理函数,传入信号值
void handler(int signo); //可以将信号值设为SIG_IGN来忽略它;设为SIG_DFL来启用默认处置
- 忽略信号:将handler的参数设为SIG_IGN来忽略对某个信号的处置
- 启用信号的默认处置:将handler的参数设为SIG_DFL来启动信号的默认处置
- 默认处置通常是收到信号后终止进程
- SIGCHLD和SIGURG(带外数据到达时发送)的默认处置是忽略信号
信号 | 描述 |
---|---|
SIGCHLD | 子进程终止时给父进程发送的信号,如果父进程没有捕获代码,则这个信号被忽略 |
SIGTERM | 关机时,init进程向系统中进程发出的信号,提示进程即将关机,进程可以捕获然后执行一些处理 |
SIGKILL(不能捕获) | 杀掉进程 |
SIGSTOP(不能捕获) | 停止进程 |
信号标志 | 描述 |
---|---|
SA_RESTART | 如果设置,由相应信号中断的系统调用将由内核自动重启(但是好像某些实现即使支持这个标志,也不一定会重启,所以不能过分依赖这个标志) |
Linux环境下开发经常会碰到很多错误(设置errno),常见错误:
错误 | 描述 |
---|---|
EAGAIN | 通常发生在非阻塞I/O中,如果数据未准备好,I/O操作会返回这个错误,提示再试一次 |
EINTR | 表示系统调用被一个捕获的信号中断,发生该错误可以继续读写套接字 |