信号驱动式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是队列中共主循环处理的数据报的总数

 #include    "unp.h"

 static int        sockfd;

 #define    QSIZE       8        /* size of input queue */
#define MAXDG 4096 /* max datagram size */ typedef struct {
void *dg_data; /* ptr to actual datagram */
size_t dg_len; /* length of datagram */
struct sockaddr *dg_sa; /* ptr to sockaddr{} w/client's address */
socklen_t dg_salen; /* length of sockaddr{} */
} DG;
static DG dg[QSIZE]; /* queue of datagrams to process */
static long cntread[QSIZE+]; /* diagnostic counter */ static int iget; /* next one for main loop to process */
static int iput; /* next one for signal handler to read into */
static int nqueue; /* # on queue for main loop to process */
static socklen_t clilen;/* max length of sockaddr{} */ static void sig_io(int);
static void sig_hup(int);

2.dg_echo函数

 void
dg_echo(int sockfd_arg, SA *pcliaddr, socklen_t clilen_arg)
{
int i;
const int on = ;
sigset_t zeromask, newmask, oldmask; sockfd = sockfd_arg;
clilen = clilen_arg; for (i = ; i < QSIZE; i++) { /* init queue of buffers */
dg[i].dg_data = Malloc(MAXDG);
dg[i].dg_sa = Malloc(clilen);
dg[i].dg_salen = clilen;
}
iget = iput = nqueue = ; Signal(SIGHUP, sig_hup);
Signal(SIGIO, sig_io);
Fcntl(sockfd, F_SETOWN, getpid());
Ioctl(sockfd, FIOASYNC, &on);
Ioctl(sockfd, FIONBIO, &on); Sigemptyset(&zeromask); /* init three signal sets */
Sigemptyset(&oldmask);
Sigemptyset(&newmask);
Sigaddset(&newmask, SIGIO); /* signal we want to block */ Sigprocmask(SIG_BLOCK, &newmask, &oldmask);
for ( ; ; ) {
while (nqueue == )
sigsuspend(&zeromask); /* wait for datagram to process */ /* 4unblock SIGIO */
Sigprocmask(SIG_SETMASK, &oldmask, NULL); Sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, ,
dg[iget].dg_sa, dg[iget].dg_salen); if (++iget >= QSIZE)
iget = ; /* 4block SIGIO */
Sigprocmask(SIG_BLOCK, &newmask, &oldmask);
nqueue--;
}
}

3.sig_io信号处理函数

因为信号时不排队的,开启信号驱动式I/O的描述符通常也被设置为非阻塞式。

这个前提下,我们把SIGIO信号处理函数编写成一个循环中执行读入操作,直到操作返回EWOULDBLOCK时才结束循环。

 static void
sig_io(int signo)
{
ssize_t len;
int nread;
DG *ptr; for (nread = ; ; ) {
if (nqueue >= QSIZE)
err_quit("receive overflow"); ptr = &dg[iput];
ptr->dg_salen = clilen;
len = recvfrom(sockfd, ptr->dg_data, MAXDG, ,
ptr->dg_sa, &ptr->dg_salen);
if (len < ) {
if (errno == EWOULDBLOCK)
break; /* all done; no more queued to read */
else
err_sys("recvfrom error");
}
ptr->dg_len = len; nread++;
nqueue++;
if (++iput >= QSIZE)
iput = ; }
cntread[nread]++; /* histogram of # datagrams read per signal */
}

4.sig_hup信号处理函数

 static void
sig_hup(int signo)
{
int i; for (i = ; i <= QSIZE; i++)
printf("cntread[%d] = %ld\n", i, cntread[i]);
}

对于TCP套接字的SIGIO信号

因为对于TCP套接字,该信号产生得过于频繁,并且它的出现并没有告诉我们发生了上面事情。因此信号驱动式I/O对于TCP套接字几乎没用。

最新文章

  1. 11.11光棍节工作心得——github/MVP
  2. Module-Zero之启动模板
  3. java length属性 length()方法 size()方法
  4. Web服务器优化
  5. [Cocoa]深入浅出 Cocoa 之 Core Data(1)- 框架详解
  6. Opencv读取视频一闪而过情况分析
  7. Cortex-M3 FLASH 日志文件系统
  8. 关于input标签的需要注意的几个小问题
  9. zoj 3870
  10. hdu 4932 Miaomiao&amp;#39;s Geometry(暴力)
  11. Python四步实现决策树ID3算法,参考机器学习实战
  12. [macOS] git忽略所有的.DS_Store文件
  13. java项目打包生成MD5文件
  14. win7生成ssh key配置到gitlab
  15. grid - 通过网格区域命名和定位网格项目
  16. Python全栈之路----Python基础元素
  17. css 按钮凹陷的感觉
  18. 分享一个Godaddy的优惠码,可以优惠35%——2013-11-23
  19. 下拉刷新 上拉更多 支持ListView GridView WebView【转载】
  20. iOS App Transprot Security

热门文章

  1. BZOJ 2752:[HAOI2012]高速公路(road)(线段树)
  2. [ZJOI2015][bzoj3924] 幻想乡战略游戏 [动态点分治]
  3. https总结
  4. vue基础教程
  5. 存储过程代码生成器Stored Procedure Generator
  6. Docker(二):Docker的用途
  7. Berkeley DB Java Edition 简介
  8. unittest框架及自动化测试
  9. react 使用antd的多选功能做一个单选与全选效果
  10. Linux中查看某个软件的安装路径