信号驱动式I/O是指进程预先告知内核,使得当某个描述符发生某事时,内核使用信号通知相关进程。
套接字的信号驱动式I/O
针对一个套接字使用信号驱动式I/O(SIGIO)要求进程执行以下3个步骤:
1.建立SIGIO信号的信号处理函数
2.设置该套接字的属主,通常使用fcntl的F_SETOWN命令设置
3.开启该套接字的信号驱动式I/O,通常通过使用fcntl的F_SETFL命令打开O_ASYNC标志完成
对于UDP套接字的SIGIO信号
在UDP上使用信号驱动式I/O是简单得。SIGIO信号在发生以下事件时产生:
1.数据报到达套接字
2.套接字上发生异步错误
因此当捕获对于某个UDP套接字的SIGIO信号时,我们调用recvfrom读入到达的数据报或者获取发生的异步错误。
使用SIGIO的UDP回射服务器程序
下面是构建一个UDP服务器的两种方式,我们的程序使用的右面的方式
1.全局声明
SIGIO信号处理函数把到达的数据放入一个队列。该队列是一个DG数据数组,我们把它作为一个环形缓冲区处理
每个DG结构包括指向所收取数据报的一个指针、该数据包的长度、指向含有客户协议地址的某个套接字地址结构的一个指针、该协议地址的大小。
iget是主循环将处理的下一个数组元素的下标,iput是信号处理函数将存放到下一个数组元素的下标,nqueue是队列中共主循环处理的数据报的总数
1 #include "unp.h" 2 3 static int sockfd; 4 5 #define QSIZE 8 /* size of input queue */ 6 #define MAXDG 4096 /* max datagram size */ 7 8 typedef struct { 9 void *dg_data; /* ptr to actual datagram */ 10 size_t dg_len; /* length of datagram */ 11 struct sockaddr *dg_sa; /* ptr to sockaddr{} w/client's address */ 12 socklen_t dg_salen; /* length of sockaddr{} */ 13 } DG; 14 static DG dg[QSIZE]; /* queue of datagrams to process */ 15 static long cntread[QSIZE+1]; /* diagnostic counter */ 16 17 static int iget; /* next one for main loop to process */ 18 static int iput; /* next one for signal handler to read into */ 19 static int nqueue; /* # on queue for main loop to process */ 20 static socklen_t clilen;/* max length of sockaddr{} */ 21 22 static void sig_io(int); 23 static void sig_hup(int);