信号驱动I/O是通过内核发送信号(如SIGIO)来通知进程某个I/O操作已准备好,而不需要进程主动去检查文件描述符的状态。该模型通常用于异步通知I/O事件的发生,避免了轮询操作,从而减少了CPU的浪费。
#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;
}