基于信号驱动式IO的监听套接字(O_ASYNC,O_NONBLOCK)

背景

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
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<fcntl.h>  
  2. #include<signal.h>  
  3. ...  
  4.   
  5. int listenfd,connfd;  
  6.   
  7. void sig_iohander(int signo)  
  8. {  
  9.     int rn;   
  10.     char buff[128];  
  11.     puts("get sigio...");  
  12.     connfd = accept(listenfd,NULL,0);  
  13.     if(connfd == -1){perror("accept");return;}  
  14.     rn = recv(connfd,buff,127,0);  
  15.     if(rn == -1) {perror("recv");return;}  
  16.     buff[rn]='\0';  
  17.     printf("recv #%s#\n",buff);  
  18.   
  19.     close(connfd);  
  20. }  
  21.   
  22. int main(int argc,char*argv[])  
  23. {  
  24.     struct sockaddr_in cliaddr,servaddr;  
  25.     int queuelen=5,i,flag;  
  26.     pid_t cpid[WORKERSIZE];  
  27.   
  28.     listenfd = socket(AF_INET,SOCK_STREAM,0);  
  29.   
  30.     signal(SIGIO,sig_iohander);  
  31.   
  32.     flag = fcntl(listenfd,F_GETFL,0);  
  33.     flag |= O_NONBLOCK | O_ASYNC;  
  34.     fcntl(listenfd,F_SETFL,flag);//将监听套接字设置为非阻塞(非阻塞是因为listenfd发生的连接可能在调用accept的时候,对方已近关闭连接了,这时候如果监听套接字为阻塞,那么进程将长期阻塞直到有新连接完成),异步IO(O_ASYNC)  
  35.   
  36.     fcntl(listenfd,F_SETOWN,getpid()); //设定listenfd上接收到的中断  
  37.   
  38. 信号的处理进程ID  
  39.   
  40.     bzero(&servaddr,sizeof(servaddr));  
  41.     servaddr.sin_family = AF_INET;  
  42.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  43.     servaddr.sin_port = htons(2989);  
  44.   
  45.     bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));  
  46.     listen(listenfd,queuelen);  
  47.   
  48.     while(scanf("%d",&i))//故意让程序阻塞于命令行io,实则等待SIGIO  
  49.   
  50. 的骚扰~  
  51.         puts("jump out of scanf block...");  
  52.       
  53.     return 0;  
  54. }  

client.c
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ...  
  2.     sockfd = socket(AF_INET,SOCK_STREAM,0);  
  3.     rc = connect(sockfd,(struct sockaddr*)&servaddr,sizeof  
  4.   
  5. (servaddr));  
  6.     if(rc == -1)   
  7.     {     
  8.         perror("connect error");  
  9.         exit(0);  
  10.     }     
  11.     printf("pid#%d connected...\n",getpid());  
  12.     char content[128];  
  13.     sprintf(content,"client pid=%d say hello...",getpid());  
  14.     send(sockfd,content,strlen(content),0);  
  15.     shutdown(sockfd,SHUT_WR);  
  16.     int rn;   
  17.     while((rn == recv(sockfd,content,127,0)))//rn == 0 : 表示服务端  
  18.   
  19. 关闭了写(FIN),即解释为EOF  
  20.     {     
  21.         content[rn] = '\0';  
  22.         puts(content);  
  23.     }     
  24.     printf("pid#%d done...\n",getpid());  
  25. ...  

测试结果:
服务端如下显示:
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...#
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值