I/O模型

首先我们将查看UNIX下可用的5种I/O模型的基本区别:

1.阻塞式I/O

2.非阻塞式I/O

3.I/O复用(select和poll)

4.信号驱动式I/O(SIGIO)

5.异步I/O(POSIX的aio_系列函数)

 

 

阻塞式I/O模型

最流行的I/O模型是阻塞式I/O模型,下面以数据报套接字作为例子,有如下的情形

 

UNP学习笔记(第六章 I/O复用)

 

 

 

非阻塞式I/O模型

进程把一个套接字设置成非阻塞式通知内核:当锁请求的I/O操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠,而是返回一个错误

 

UNP学习笔记(第六章 I/O复用)

前三次调用recvfrom时没有数据可返回,因此内核转而立即返回一个EWOULDBLOCK错误。

 

 

 

 

I/O复用模型

我们可以调用select和poll,阻塞在这两个系统调用中的某一个之上,而不是在真正的I/O系统调用上

 

UNP学习笔记(第六章 I/O复用)

 

下面小节将详细讲这两个函数的用法

 

 

 

信号驱动式I/O模型

我们也可以用信号,让内核在描述符就绪时发送SIGIO信号通知我们。

 

UNP学习笔记(第六章 I/O复用)

 

在信号发生之后,在信号处理函数中调用recvfrom读取数据报。

 

 

 

 

异步I/O模型

信号驱动式I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知我们I/O操作何时完成。

 

UNP学习笔记(第六章 I/O复用)

 

 

 

 

select函数

之前apue的学习笔记也有详细的用法 http://www.cnblogs.com/runnyu/p/4645754.html

#include <sys/select.h>
int select(int maxfdp1,fd_set *restrict readfds,fd_set *restrict writefds,fd_set *restrict exceptfds,struct timeval *restrict tvptr);

参数tvptr指定愿意等待的时间,有下面3种情况

1.tvptr==NULL 永远等待,直到所指定的描述符中的一个已经准备好或捕捉到一个信号返回。如果捕捉到一个信号,则select返回-1,errno设置为EINTR

2.tvptr->tv_sec==0 && tvptr->tv_usec==0 不等待,测试所有指定的描述符并立即返回

3.tvptr->tv_sec!=0 || tvptr->tv_usec!=0  等待指定的秒数和微秒数。当指定的描述符之一已准备好,或当指定的时间值已经超过时立即返回

中间3个参数readfds、writefds和exceptfds是指向描述符集的指针。这3个描述符集说明了我们关心的可读、可写和处于异常条件的描述符集合。

对于描述符集fd_set结构,提供了下面4个函数

#include <sys/select.h>
int FD_ISSET(int fd,fd_set *fdset);
void FD_CLR(int fd,fd_set *fdset);
void FD_SET(int fd,fd_set *fdset);
void FD_ZERO(fd_set *fdset);

select第一个参数maxfdp1的意思是“最大文件描述符编号值加1”,在上面3个描述符集中找到最大描述符编号值,然后加1就是第一个参数值。

select有3个可能的返回值

1.返回值-1表示出错。如果在所指定的描述符一个都没准备好时捕捉到一个信号,则返回-1

2.返回0表示没有描述符准备好,指定的时间就过了。

3.一个正返回值说明了已经准备好的描述符数,在这种情况下,3个描述符集中依旧打开的位对应于已准备好的描述符。

 

 

 

使用select修订str_cli函数

新版本改为阻塞于select调用,或是等待标准输入可读,或是等待套接字可读。

 

UNP学习笔记(第六章 I/O复用)

代码如下

 1 #include    "unp.h"
 2 
 3 void
 4 str_cli(FILE *fp, int sockfd)
 5 {
 6     int            maxfdp1;
 7     fd_set        rset;
 8     char        sendline[MAXLINE], recvline[MAXLINE];
 9 
10     FD_ZERO(&rset);
11     for ( ; ; ) {
12         FD_SET(fileno(fp), &rset);
13         FD_SET(sockfd, &rset);
14         maxfdp1 = max(fileno(fp), sockfd) + 1;
15         Select(maxfdp1, &rset, NULL, NULL, NULL);
16 
17         if (FD_ISSET(sockfd, &rset)) {    /* socket is readable */
18             if (Readline(sockfd, recvline, MAXLINE) == 0)
19                 err_quit("str_cli: server terminated prematurely");
20             Fputs(recvline, stdout);
21         }
22 
23         if (FD_ISSET(fileno(fp), &rset)) {  /* input is readable */
24             if (Fgets(sendline, MAXLINE, fp) == NULL)
25                 return;        /* all done */
26             Writen(sockfd, sendline, strlen(sendline));
27         }
28     }
29 }
View Code

相关文章:

  • 2021-10-16
  • 2022-03-02
  • 2021-05-21
  • 2021-08-21
  • 2021-11-29
  • 2021-12-22
  • 2021-09-07
猜你喜欢
  • 2021-10-04
  • 2021-11-02
  • 2021-12-05
  • 2022-02-10
  • 2021-08-04
  • 2021-06-23
  • 2022-12-23
相关资源
相似解决方案