IO模型:

image.png

阻塞式:

最传统的IO,一直等数据

非阻塞式:

把阻塞改成轮询,还是没什么意义

信号驱动式:

当可以进行IO的时候,内核通知进程

多路复用:

阻塞在select上而不是单个IO上(我们可能需要处理大量的IO,比如服务器可能处理多个客户端的输入,这时我们不能阻塞在一个IO上)

异步IO:

完成IO后内核通知进程。和信号驱动式的区别在于信号驱动式告诉进程什么时候可以开始。异步IO直接是内核做完所有工作告诉进程。

Select:

image.png

image.png

image.png

image.png
注意,这也是select被epoll干掉的原因之一。fd太小了。

shutdown函数(参考书)

close把套接字文件描述符的引用计数-1,这就是说不是close后马上就能关掉套接字或者说TCP连接的。shutdown直接关闭TCP连接,不管你引用计数的事情。
同时,因为TCP是全双工的,所以shutdown可以只关读/写,也就是某个方向。

客户端服务器编程模型

我们可以做一个单线程的循环,去接收请求,也可以对每个客户端请求新开一个线程或者进程。具体怎么选呢?请看图
image.png
个人的理解就是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可通过设置第三个参数而变成不阻塞的。