IO模型:
阻塞式:
非阻塞式:
信号驱动式:
多路复用:
阻塞在select上而不是单个IO上(我们可能需要处理大量的IO,比如服务器可能处理多个客户端的输入,这时我们不能阻塞在一个IO上)
异步IO:
完成IO后内核通知进程。和信号驱动式的区别在于信号驱动式告诉进程什么时候可以开始。异步IO直接是内核做完所有工作告诉进程。
Select:
注意,这也是select被epoll干掉的原因之一。fd太小了。
shutdown函数(参考书)
close把套接字文件描述符的引用计数-1,这就是说不是close后马上就能关掉套接字或者说TCP连接的。shutdown直接关闭TCP连接,不管你引用计数的事情。
同时,因为TCP是全双工的,所以shutdown可以只关读/写,也就是某个方向。
客户端服务器编程模型
我们可以做一个单线程的循环,去接收请求,也可以对每个客户端请求新开一个线程或者进程。具体怎么选呢?请看图
个人的理解就是TCP比较慢,UDP比较快,所以对于UDP可以不开新的线程。
fork
这个实在太基础了。。调用一次返回两次,子进程返回0,父进程返回子进程pid。之所以这么设计是因为子进程可以通过getppid(大概叫这个名吧?)获取父进程的pid,而父进程没这种函数,所以需要给父进程返回子进程的pid。
信号
信号是一个进程得到的通知,方向可以是内核到线程,也可以是线程到内核。
SIGCHLD信号:内核发给终止的进程的父进程的信号。
信号处理方式
自定义信号处理函数
忽略->SIG_IGN
缺省方式->SIG_DFL
修改对信号的定义->signal或sigaction
sigaction
int sigaction(int signum,const struct sigaction act ,struct sigaction oldact);
struct sigaction 比较复杂
慢系统调用
能永久阻塞的系统调用叫做慢系统调用。
包括accept read write select
当进程捕获到中断并处理完中断时,有些系统下这些慢系统调用会返回EINTER,有些系统下会自动继续执行。
POSIX信号处理语义
同一个signum的信号只会处理第一个,处理第一个的时候进入到block状态,后续所有同类的信号全部丢弃。
其他signum(也就是其它类)的会被pending
并发服务器问题
子进程结束的时候父进程会收到SIGCHLD,这时候父进程要回收资源,避免泄露。
如何处理终止的子进程?
随机处理一个 wait
处理某个子进程 waitpid
waitpid可通过设置第三个参数而变成不阻塞的。