spacer.gif实验信号驱动I/O

信号驱动I/O 模型

使用信号驱动I/O 时,内核通过发送SIGIO 信号通知应用进程,于是应用进

程开始读取数据,信号驱动I/O 有时也成为异步I/O

程序首先要允许套接字使用信号驱动模式,通过sigacton 调用注册一个

SIGIO 处理程序,当有数据到达后,系统向应用程序交付一个SIGIO 信号,应用

程序可以在信号处理程序中读取套接字数据。如下图所示:

内核

应用

sigaction

SIGIO

read in signal handler

拷贝数据到用户空间

return  success

处理数据

设置套接字工作于信号驱动I/O 模式

1)注册SIGIO 信号处理程序

2使用fcntl F_SETOWN 命令,设置套接字所有者为当前进程。

3使用fctnl F_SETFL 命令,设置O_ASYNC 标志,允许套接字使用信号

驱动I/O

UDP 编程中可以使用信号驱动,此时SIGIO 产生于下面两种情况

1)套接字收到一个数据包

2)套接字上发生了异步错误

对于TCP 套接字,信号驱动I/O 就没有意义了,因为下面种情况都会产生

SIGIO,而且很难(有时甚至无法)区分是什么情况导致的:

1)监听套接字完成了一个连接请求

2)收到了一个断连请求

3)断连操作完成

4)套接字收到数据

5)有数据从套接字发出

程序示例

#include <stdio.h>



spacer.gif#include <stdlib.h>

#include <sys/socket.h>

#include <signal.h>

#include <string.h>

#include <arpa/inet.h>

#include <fcntl.h>

#define MAXBUF 512

#define PORT 5001

int s;

char buf[MAXBUF];

void do_sigio(int sig)

{

struct sockaddr_in cli;

int len=sizeof cli;

int n=recvfrom(s,buf,MAXBUF,0,(struct  sockaddr*)&cli,&len);

buf[n]=0;

printf("%s from %s:%u\r\n",buf,inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));

}

int main()

{

s=socket(AF_INET,SOCK_DGRAM,0);

struct sigaction act;

memset(&act,0,sizeof(act));

act.sa_handler=do_sigio;

act.sa_flags=0;

int sret=sigaction(SIGIO,&act,NULL);

if(sret==-1){printf("install  signal error !\r\n");exit(-1);};

int r1=fcntl(s,F_SETOWN,getpid());//设置套接字的属主进程,为该jincfc

int flag;

int r2=fcntl(s,F_GETFL,&flag);

flag|=O_ASYNC|O_NONBLOCK;

int r3=fcntl(s,F_SETFL,flag);//设置该套接字为信号驱动模式和非阻塞模式

if(r1<0||r2<0||r3<0){printf("设置套接字属性错误!\r\n");exit(-1);};

struct sockaddr_in svr;

inet_aton("0.0.0.0",&svr.sin_addr);

svr.sin_port=htons(PORT);

svr.sin_family=AF_INET;

bind(s,(struct sockaddr*)&svr,sizeof svr);

while(1)

{

}

}