socket信号驱动
为了使一个套接字能够使用信号驱动I/O,至少需要以下3步操作。
- 1.安装SIGIO信号
- 2.套接字的拥有者设定为当前进程。因为SIGIO信号只会送到socket拥有者进程. 通过fcntl的F_SETOWN
- 3.套接字必须被允许使用异步I/O。 通过fcntl的F_SETFL,设置为O_ASYNC
在UDP通信中,下面情况会产生SIGIO信号
在TCP通信中,下面情况会产生SIGIO信号
例子:
下面的代码好奇怪,说是UDP的,但是发送接收用的是send, recv 而且客户端还跟服务器连接了;说是TCP,但是socket建立的时候用的是SOCK_DGRAM.
而且代码是可以跑通的。
服务器:
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<netinet/tcp.h> #include<sys/socket.h> #include<sys/wait.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/time.h> #include<netdb.h> #include<fcntl.h> #include<signal.h> #include<sys/ioctl.h> #define MAX_LENTH 1500 //针对SIGIO信号处理 static int nqueue = 0; void sigio_handler(int signum) { if(signum == SIGIO) nqueue++; printf("signum = %d, nqueue = %d ", signum, nqueue); //打印信号值 return; } static recv_buf[MAX_LENTH]; int main(int argc, char *argv[]) { int sockfd, on = 1; struct sigaction action; sigset_t newmask, oldmask; struct sockaddr_in ser_addr; if(argc != 3) { printf("use: %s ip_add port ", argv[0]); exit(EXIT_FAILURE); } memset(&ser_addr, 0, sizeof(ser_addr)); ser_addr.sin_family = AF_INET; //使用IPv4 ser_addr.sin_port = htons(atoi(argv[2])); if(inet_aton(argv[1], (struct in_addr *)&ser_addr.sin_addr.s_addr) == 0) { perror(argv[1]); exit(EXIT_FAILURE); } //创建socket if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(EXIT_FAILURE); } //绑定IP地址 if(bind(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) == -1) { perror("bind"); exit(EXIT_FAILURE); } memset(&action, 0, sizeof(action)); action.sa_handler = sigio_handler; action.sa_flags = 0; //安装信号 sigaction(SIGIO, &action, NULL); //设置socket拥有者 if(fcntl(sockfd, F_SETOWN, getpid()) == -1) { perror("fcntl F_SETOWN"); exit(EXIT_FAILURE); } //设置socket为信号驱动型 if(ioctl(sockfd, FIOASYNC, &on) == -1) { perror("ioctl FIOASYNC"); exit(EXIT_FAILURE); } sigemptyset(&oldmask); sigemptyset(&newmask); sigaddset(&newmask, SIGIO); printf("get ready "); while(1) { int len; //设置当前阻塞的信号 sigprocmask(SIG_BLOCK, &newmask, &oldmask); //等待信号 while(nqueue == 0) sigsuspend(&oldmask); memset(recv_buf, '