背景
Source: http://blog.csdn.net/ordeder/article/details/22733077
(Unix网络编程卷1说明如下)
设置套接字信号驱动式io(SIGIO)需要三个步骤:
1.建立SIGIO信号的处理函数
2.设置套接字的属主,即fcntl:F_SETOWN
3.开启套接字的信号驱动是IO,即:fcntl:O_ASYNC
引起套接字产生SIGIO信号的情况有:
1监听套接字上有连接请求已完成
-----------------------
2断连请求已发起
3断连请求已完成
4连接的一半已经关闭
----------------------
5数据到达套接字
6数据从套接字发出
7发生异步错误
小结
由1可得,监听套接字适合异步信号IO;
2-7可得异步IO不适合TCP连接套接字;
5-7可得,UDP适合异步信号IO
监听套接字的异步信号IO
server.c
#include<fcntl.h> #include<signal.h> ... int listenfd,connfd; void sig_iohander(int signo) { int rn; char buff[128]; puts("get sigio..."); connfd = accept(listenfd,NULL,0); if(connfd == -1){perror("accept");return;} rn = recv(connfd,buff,127,0); if(rn == -1) {perror("recv");return;} buff[rn]='\0'; printf("recv #%s#\n",buff); close(connfd); } int main(int argc,char*argv[]) { struct sockaddr_in cliaddr,servaddr; int queuelen=5,i,flag; pid_t cpid[WORKERSIZE]; listenfd = socket(AF_INET,SOCK_STREAM,0); signal(SIGIO,sig_iohander); flag = fcntl(listenfd,F_GETFL,0); flag |= O_NONBLOCK | O_ASYNC; fcntl(listenfd,F_SETFL,flag);//将监听套接字设置为非阻塞(非阻塞是因为listenfd发生的连接可能在调用accept的时候,对方已近关闭连接了,这时候如果监听套接字为阻塞,那么进程将长期阻塞直到有新连接完成),异步IO(O_ASYNC) fcntl(listenfd,F_SETOWN,getpid()); //设定listenfd上接收到的中断 信号的处理进程ID bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(2989); bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); listen(listenfd,queuelen); while(scanf("%d",&i))//故意让程序阻塞于命令行io,实则等待SIGIO 的骚扰~ puts("jump out of scanf block..."); return 0; }
client.c
... sockfd = socket(AF_INET,SOCK_STREAM,0); rc = connect(sockfd,(struct sockaddr*)&servaddr,sizeof (servaddr)); if(rc == -1) { perror("connect error"); exit(0); } printf("pid#%d connected...\n",getpid()); char content[128]; sprintf(content,"client pid=%d say hello...",getpid()); send(sockfd,content,strlen(content),0); shutdown(sockfd,SHUT_WR); int rn; while((rn == recv(sockfd,content,127,0)))//rn == 0 : 表示服务端 关闭了写(FIN),即解释为EOF { content[rn] = '\0'; puts(content); } printf("pid#%d done...\n",getpid()); ...
测试结果:
服务端如下显示:
get sigio...
recv #client pid=2236 say hello...#
get sigio...
recv #client pid=2237 say hello...#
get sigio...
recv #client pid=2238 say hello...#
get sigio...
recv #client pid=2239 say hello...#
get sigio...
recv #client pid=2240 say hello...#
get sigio...
recv #client pid=2241 say hello...#
get sigio...
recv #client pid=2242 say hello...#
recv #client pid=2236 say hello...#
get sigio...
recv #client pid=2237 say hello...#
get sigio...
recv #client pid=2238 say hello...#
get sigio...
recv #client pid=2239 say hello...#
get sigio...
recv #client pid=2240 say hello...#
get sigio...
recv #client pid=2241 say hello...#
get sigio...
recv #client pid=2242 say hello...#