UNP_25_信号驱动式IO
25.1 概述
信号驱动式 I/O 是指进程预先告知内核,使得当某个描述符上发生某事时,内核使用信号通知相关进程。
25.2 套接字的信号驱动式 I/O
针对一个套接字使用信号驱动式I/O,要求进程执行以下3个步骤:
- 建立SIGIO信号处理函数
signal(SIGIO, sig_io);
- 设置该套接字的属主进程,通常使用fcntl的F_SETOWN命令设置
fcntl(sockfd, F_SETOWN, getpid());
- 开启该套接字的信号驱动式I/O,通常通过使用fcntl的F_SETFL命令打开O_ASYNC标志
const int on = 1;
ioctl(sockfd, O_ASYNC, &on);
尽管很容易把一个套接字设置成以信号驱动式 I/O 模式工作,确定那些条件导致内核产生递交给套接字属主的 SIGIO 信号却不是简单的事情。这种判断取决于支撑协议
对于 UDP 套接字的 SIGIO 信号
在UDP上使用信号驱动式 I/O 比较简单的。SIGIO 信号在发生以下事件时产生
- 数据报到达套接字
- 套接字上产生异步错误
因此当捕获对于某个 UDP 套接字上的 SIGIO 信号时,我们调用 recvfrom 等读入到达的数据报,或者获取发生的异步错误。UDP 异步错误的前提是 UDP 套接字已经连接
对于 TCP 套接字的 SIGIO 信号
总的来说,信号驱动式 I/O 对于 TCP 套接字近乎无用,因为该信号产生得过于频繁,仅通过 SIGIO 信号不能区分具体是哪种事件
- 监听套接字上某个连接请求请求已经完成
- 某个断连接请求已经发起
- 某个断连接请求已经完成
- 某个连接之半已经关闭
- 数据到达套接字
- 数据已经从套接字发送走(即输出缓冲区有空闲空间)
- 发生某个异步错误
从上面看出,我们只能对监听套接字使用 SIGIO,因为对于监听套接字产生 SIGIO 的唯一条件一定是某个新连接的完成。
25.3 使用 sigio 的 udp 回射服务器程序
书上给出了一个使用 SIGIO 信号的 UDP 回射服务器,使用了信号驱动 I/O。可以进行参考,实例比较简单
小结
信号驱动式 I/O 就是让内核在套接字上发生“某事”时使用 SIGIO 信号通知进程
- 对于已连接 TCP 套接字,可以导致的事件众多,使得这个特性基本无用
- 对于监听 TCP 套接字,这种通知发生在有一个新连接已经准备好接收时
- 对于 UDP 套接字,这种通知通常意味着到达一个数据报,或者是一个异步的错误,这两种情况我们都是用 recvfrom 进行处理