> For the complete documentation index, see [llms.txt](https://xd96dx.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xd96dx.gitbook.io/docs/c-c++/wang-luo-bian-cheng/linux-wang-luo/signaldriven-io-model-xin-hao-qu-dong.md).

# Signal-Driven I/O Model(信号驱动)

信号驱动I/O是通过内核发送信号（如SIGIO）来通知进程某个I/O操作已准备好，而不需要进程主动去检查文件描述符的状态。该模型通常用于异步通知I/O事件的发生，避免了轮询操作，从而减少了CPU的浪费。

### code

```cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>

#define PORT 8080

int sockfd;

// 信号处理函数
void sigio_handler(int signo) {
    char buffer[1024];
    int n;

    // 读取套接字数据
    n = read(sockfd, buffer, sizeof(buffer) - 1);
    if (n < 0) {
        if (errno == EAGAIN) {
            printf("No data available\n");
        } else {
            perror("Read error");
        }
        return;
    }
    buffer[n] = '\0';  // Null terminate the string
    printf("Received data: %s\n", buffer);
}

int main() {
    struct sockaddr_in server_addr;
    struct sigaction sa;

    // 创建一个套接字
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket failed");
        exit(EXIT_FAILURE);
    }

    // 配置服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    // 绑定套接字到端口
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 设置套接字为非阻塞模式
    if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) {
        perror("fcntl failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 设置套接字为异步I/O模式，信号SIGIO将在I/O事件发生时发送
    if (fcntl(sockfd, F_SETFL, FASYNC) < 0) {
        perror("fcntl failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 注册SIGIO信号处理函数
    sa.sa_handler = sigio_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGIO, &sa, NULL) < 0) {
        perror("sigaction failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 启动监听
    if (listen(sockfd, 5) < 0) {
        perror("Listen failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("Server listening on port %d...\n", PORT);

    // 服务器主循环，等待SIGIO信号
    while (1) {
        pause();  // 等待信号到达
    }

    close(sockfd);
    return 0;
}

```

1. 代码中, 定义了 sigio\_handler函数，用于处理`SIGIO`信号，当I/O操作准备好时，内核会发送此信号，并触发该函数，读取数据并进行处理
2. `fcntl(sockfd, F_SETFL, O_NONBLOCK)`：设置套接字为非阻塞模式\
   `fcntl(sockfd, F_SETFL, FASYNC)`：使套接字支持异步I/O，进程可以通过信号接收I/O事件通知
3. 通过`sigaction`注册处理`SIGIO`信号的回调函数。每当I/O事件发生时，内核会发送`SIGIO`信号，进程就会执行该信号处理函数
