UNP_25_信号驱动式IO

Posted on Mar 25, 2020

25.1 概述

  信号驱动式 I/O 是指进程预先告知内核,使得当某个描述符上发生某事时,内核使用信号通知相关进程。

25.2 套接字的信号驱动式 I/O

  针对一个套接字使用信号驱动式I/O,要求进程执行以下3个步骤:

  1. 建立SIGIO信号处理函数
    signal(SIGIO, sig_io);
  1. 设置该套接字的属主进程,通常使用fcntl的F_SETOWN命令设置
    fcntl(sockfd, F_SETOWN, getpid());
  1. 开启该套接字的信号驱动式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 进行处理