1. 创建套接口并设置其为非阻塞模式。
2使用sigaction函数或signal函数设置相应的信号处理程序
3.将套接口与信号关联起来,使用fcntl函数设置F_SETOWN标志和FASYNC标志。F_SETOWN标志将所有发送给进程的信号都转发给指定的进程ID,而FASYNC标志则允许套接口被设置为异步通知方式。
4. 等待信号触发。当套接口上有可用数据时,内核将发送SIGIO信号给进程,此时信号处理程序将被调用,并且可以执行相应的操作。
当数据准备好时,进程会收到一个SIGIO信号
优势在于等待数据报到达(第一阶段)期间,进程可以继续执行,不被阻塞。免去了select的阻塞与轮询,当有活跃套接字时,再由注册的handler 处理, 无需进程主动去check活跃的socket,把检查工作交给内核,进程只需要确定合适处理拷贝即可
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#define BUF_SIZE 1024
static int fd;
static char buffer[BUF_SIZE];
void sigio_handler(int signum)
{
int len = read(fd, buffer, BUF_SIZE);
if (len > 0) {
printf("Received data: %s\n", buffer);
}
}
int main()
{
fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(1);
}
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
signal(SIGIO, sigio_handler);
while (1) {
sleep(1);
}
close(fd);
return 0;
}
O_ASYNC标志是POSIX规范中比较新的内容,支持该标志的系统不多,后面我们会改动ioctl的FIOASYNC请求代为开启信号驱动式I/O
在TCP中的使用
信号驱动式I/O对于TCP套接字产生的作用不大。因为该信号在TCP套接字中产生的过于频繁。
以下条件均会导致对一个TCP套接字产生SIGIO信号:
监听套接字上某个连接请求已经完成;
某个断连请求已经发起;
某个断连请求已经完成;
某个连接之半已经关闭;
数据到达套接字;
数据已经从套接字发送走;
发生某个异步错误。
这么多条件都会触发SIGIO信号,导致应用进程对该信号一头雾水,没法确定套接字具体发生了什么事情。
不过可以对TCP监听套接字可以使用SIGIO,因为对于监听套接字,产生SIGIO信号的唯一条件是某个新连接完成了。这样就可以在SIGIO信号处理函数中获取新连接了