第十七篇:IO复用之select实现

前言

       在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识。

       接下来,我要在一个具体的并发客户端中实现它(基于select函数),使得一旦服务器中的客户进程被终止的时候,客户端这边立即得到通知并返回异常。

select函数

函数原型:int select ( int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout )

包含头文件:sys/select.h  sys/time.h ( 两个都要包含 )

参数说明:maxfdp1表示监听描述符个数( 一般直接赋予最大描述符号的值+1 ),中间几个参数表示具体的监听描述符集( 读/写/异常描述符集,本质是位向量组 ),最后一个参数表示监听的时间限制结构体。

配套使用宏:

1. void FD_ZERO ( fd_set *fdset ) 监听描述符集清零

2. void FD_SET ( int fd, fd_set *fset ) 注册要监听的描述符

3. void FD_CLR ( int fd, fd_set *fdset ) 注销不要监听的描述符

4. int FD_ISSET ( int fd, fd_set *fdset ) 判断某个监听信号是否接收到( 一般用于在select函数调用后某个信号是否接收到判断 )

返回值:返回已经就绪的描述符的个数,如果是定时器到时则返回0,出错则返回-1。

大致用法:

1. 定义一个空的描述符集

以下部分循环:

2. 注册要监听的描述符

3. 调用select函数

4. 依次编写IO处理代码( 一般是if ( FD_ISSET(描述符), &监听描述符集 ) { } 这样的结构 )。

代码实现

       下面的代码对之前的客户端代码做了修改,增加了基于select函数的IO复用机制:

 1 #include    "unp.h"
 2 
 3 void
 4 str_cli(FILE *fp, int sockfd)
 5 {
 6     int            maxfdp1;
 7     // 定义描述符集
 8     fd_set        rset;
 9     char        sendline[MAXLINE], recvline[MAXLINE];
10 
11     // 清空描述符集
12     FD_ZERO(&rset);
13     for ( ; ; ) {
14         // 注册要监听的两个描述符
15         FD_SET(fileno(fp), &rset);
16         FD_SET(sockfd, &rset);
17         // 计算最大描述符并将它+1后作为select函数的第一个参数
18         maxfdp1 = max(fileno(fp), sockfd) + 1;
19         // 调用并阻塞于select函数
20         Select(maxfdp1, &rset, NULL, NULL, NULL);
21 
22         // 读取回射以及处理TCP分节
23         if (FD_ISSET(sockfd, &rset)) {    
24             if (Readline(sockfd, recvline, MAXLINE) == 0)
25                 err_quit("str_cli: server terminated prematurely");
26             Fputs(recvline, stdout);
27         }
28 
29         // 处理用户输入
30         if (FD_ISSET(fileno(fp), &rset)) { 
31             if (Fgets(sendline, MAXLINE, fp) == NULL)
32                 return;        
33             Writen(sockfd, sendline, strlen(sendline));
34         }
35     }
36 }

运行测试

       经过测试,发现当服务器杀死客户端子进程后,客户端这边立刻报错并退出了程序。

posted @ 2017-05-19 13:50  穆晨  阅读(541)  评论(0编辑  收藏  举报