经过几天对I/O复用这章内容的学习,了解select、pselect、poll函数
I/O复用主要用于有多个描述字的场合,在前面的回射程序的学习当中,我们可以发现客户端程序要处理2个描述字,
其中一个是用于处理客户端的标准输入
另外一个是用于处理套接口传递过来的数据
基于上面的情况,我们可以发现有这样一种情况,如果服务端程序提前断开,例如输入ctrl+C,那么客户端程序依然阻塞于
标准输入,即等待用户输入,但这时输入已经毫无意义,因为服务器程序已经停止工作了;
这章的几个函数就是用于处理这种情况的,即当任何一个描述字当前的状态为准备好,那么程序就可以处理它,而不是一直
阻塞于未准备好的描述字
在unix中有5个基本的I/O模型
1、阻塞I/O
2、非阻塞I/O
3、I/O复用
4、信号驱动I/O
5、异步I/O
我们这章主要用的是I/O复用(select/poll),其他的I/O模型在这里就不介绍了!
我们阻塞于select调用,等待数据报套接口可读,当select返回套接口可读的条件时,我们调用recvfrom将数据报拷贝到应用缓冲区中
使用它的好处是我们可以等待多个描述字准备好
下面简单介绍一下select函数的几个参数说明
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *errorfds, struct timeval *timeout);
还是按照书上说的顺序简单介绍下几个参数的含义
1、timeout参数是描述字准备要花费的时间,有三种取值(NULL,{*,*},{0,0}),具体的可自行查找,就不做详细的介绍了
2、readfds,writefds,errorfds指定我们要让内核测试读、写和异常条件所需的描述字,类型是集合类型的,可以用以下几个函数对其进行操作
void FD_CLR(int fd, fd_set *fdset);-->turn off the bit for fd in fd_set
int FD_ISSET(int fd, fd_set *fdset);-->is the bit for fd in fd_set?
void FD_SET(int fd, fd_set *fdset);-->turn on the bit for fd in fd_set
void FD_ZERO(fd_set *fdset);-->clear all bits in fd_set
3、nfds是指定被测试的描述字的个数,它的值是最大描述字的值加1
下面的表格是摘自书上的小结
其中待处理错误和TCP外带数据还是有点不理解
在了解了这个函数之后,作者就对前面的回射程序的客户端输出str_cli进行修改,使其能检测多个描述字的状态,并在服务器退出后能迅速退出,而不是阻塞在等待标准输入的输入
下面就是几个关键的代码片断
fp代表标准输入的描述字
sockfd代表套接口的描述字
rset代表描述字集合
FD_ZERO(&rset);
FD_SET(fileno(fp),&rset);
FD_SET(sockfd,&rset);
maxfdp1=max(fileno(fp),sockfd)+1;//select的第一个参数,描述字中最大值加1
select(maxfdp1,&rset,NULL,NULL,NULL);
//完成上面的代码以后就开始检测各个描述字的状态,看其是否可读
if(FD_ISSET(fileno(fp),&rset)
{
//do something
}
if(FD_ISSET(sockfd,&rset)
{
//do something
}
下面为了改造程序,使其能够进行批量输入,即能一次输入多行,还要了解2个函数shutdown和close
区别:
1、close将描述字的访问计数减一,仅在计数器为0时关闭套接口
2、close终止了数据传送的2个方向:读和写,而shutdown可以只终止一个方向的连接,这就是其参数howto设置的
howto的选项有如下几种:
1、SHUT_RD -->关闭连接的读的一半
2、SHUT_WR -->关闭连接的写的一半
3、SHUT_RDWR -->连接的写一半和读一半都关闭
作者是通过改造str_cli的函数来介绍shutdown和select的使用的,但书上的例子中少了个关键字else,导致输入一行就输出一行,没有批量输入的现象,查了很长时间才找到那个丢失的else(第12行)
但是我发现,这个批量输入只能进行输入一次操作,当我输入ctrl+d的时候,输出了以前输入的多行,但是程序就退出了(需要改造,思考中)
这个程序的主要思想就是,通过一开关先对标准输入进行select操作(FD_SET(fileno(fp),&rset)),当输入ctrl+d,开关关闭,关闭连接的写这一半(shutdown(sockfd,SHUT_WR);),清除select中对标准输入的操作的标志(FD_CLR(fileno(fp),&rset);),设置select对套接口的操作(FD_SET(sockfd,&rset);).......
这就是对select的简单介绍和一些应用,不能一次写的太多,下次再说下如何利用select替代服务端的fork操作......
posted on 2007-09-08 09:56
LG 阅读(383)
评论(0) 编辑 收藏 引用 所属分类:
UnixProgram