1. I/O多路转接
如果我们想从多个文件描述符读或写数据,如果我们用以前学过的函数(read,write等)去处理可能会阻塞在一个文件描述符上,不能处理其他的文件描述符。那是因为我们以前学的I/O处理函数,都是阻塞的I/O处理函数,它们的特点是,如果缓冲区里有数据它们就会把数据写到文件中,如果缓存区没有数据他们就会等待(阻塞)直到有数据可读。这就造成了他们无法对多个文件描述符进行操作。而对多个文件描述符进行操作在网络通信方面却是执关重要的。
一种比较好的解决方案就是I/O多路转接技术。它现构造一张有关文件描述符的列表,然后调用一个函数,直到这些描述符中的一个已经准备好进行I/O时,该函数才返回。在返回时,它告诉进程那些描述符已经准备好可以进行I/O。poll,selsct,pselect这三个函数使我们能够执行I/O多路转接,下面就分别介绍它们。
2.
名称::
|
select
|
功能:
|
指行I/O多路转接
|
头文件:
|
#include <sys/select.h>
|
函数原形:
|
int select(int maxfdpl,fd_set *restrict readfds,fd_set *restrict writefds,fd_set *testrict exceptfds,struct timeval *testrict tvptr);
|
参数:
|
maxfdpl最大描述符加1
readfds读描述符集
writefds写描述符集
excepfds异常描述符集
tvptr愿意等待的时间
|
返回值:
|
准备就绪的文件描述符数,若超时则返回0,若出错则返回-1
|
select函数使我们可以执行I/O多路转接。传向select的参数告诉内核:我们所关系的描述符。对于每个描述符我们所关心的状态。以及我们愿意等待的时间。从select返回时,内核告诉我们:以准备好的描述符的数量。对于读、写或异常这三个状态中的每一个,那些描述符已经准备好。
这个函数比较复杂,我们一个一个参数的看。
第一个参数maxfdp1的意思是“最大描述符加1”。也可将第一个参数设置为FD_SETSIZE,这是<sys/select.h>中的一个常数,它说明了最大的描述符数(经常是1024)。如果将第三个参数设置为我们所关注的最大描述符编号值加一,内核就只需在此范围内寻找打开的位,而不必在三个描述符集中的数百位内搜索。
中间的三个参数readfds、writefds和exceptfds是指向描述符集的指针。这三个描述符集说明了我们关心的可读(readfds)、可写(writefd)或处于异常条件(wxcepfds)的各个描述符。每个描述符集存放在一个fd_set数据类型中。这种结构相当于一个描述符的数组,它为每个可能的描述符设置1位。
fd0fd1fd2fd3fdn
readfdsà
fd0fd1fd2fd3fdn
writefdsà
fd0fd1fd2fd3fdn
excepfdsà
可用下面4个函数对描述符集进行操作。
select的中间三个参数中的任意一个或全部都可以是空指针,这表示对相应状态不关系。如果所有三个指针都是空指针,则select提供了较sleep更精确的计时器。其等待时间可以小于1秒。
tuptr指定最后等待的时间,它的结构是:
struct timeval{
long tv_sec;秒
long tv_usec;微秒
};
有三种情况:
(1) tvptr==NULL:永远等待。如果捕捉到一个信号则中断此无限等待。当所指定的描述符中的一个已经准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回-1,errno设置为EINTR.
(2) tvptr->tv_sec==0&&tvptr_usec==0完全不等待。测试所有的描述符并立即返回。这是得到多个描述符的状态而不阻塞select函数的轮询方法。
(3)tvptr->tv_sec!=0||tvptr_usec!=0等待指定的秒数或微秒数。当指定的描述符之一已准备好,或当指定的时间值已超过时立即返回。如果在超时还没有一个描述符准备好,则返回值是0。
3.
名称::
|
FD_ISSET/FD_CLR/FD_SET/FD_ZERO
|
功能:
|
描述符集处理函数
|
头文件:
|
#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);
|
参数:
|
fdset描述符集
fd描述符
|
返回值:
|
若fd在描述符集中则返回非0值,否则返回0(FD_ISSET)
|
调用FD_ZERO将一个指定的fd_set变量的所有位设置为0。调用FD_SET设置一个fd_set变量的指定位。调用FD_CLR将一指定位清除。最后调用FD_ISSET测试一指定位是否设置。声明了一个描述符集后,必须用FD_ZERO清除其所有位,然后在其中设置我们关心的各个位。
下面是select函数实现I/O多路转接的一个例子
/*12_3.c*/
#include <sys/time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int keyboard;
int ret=0;
char c;
fd_set readfd;
struct timeval timeout;
if((keyboard=open(“/dev/tty”,O_RDONLY|O_NONBLOCK))<0) /*打开标准输入(键盘)的文件描述符*/
exit(1);/如果失败则退出程序*/
while(1)
{
timeout.tv_sec=3;/*设置等待时间为3秒*/
timeout.usec=0;
FD_ZERO(&readfd);/*初始化描述符集*/
FD_SET(keyboard,&readfd);/*把标准输入(键盘)加入到描述符集中*/
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);
if(ret==0)/*如果超时打印下面的语句*/
printf(“Time out!\n”);
if(FD_ISSET(keyboard,&readfd))/*如果描述符集readfd的keyboard位被设置*/
{
read(keyboard,&c,1);/*从键盘上读如一个字符*/
if(c==’\n’)
continue;
printf(“You input is %c\n”,c);
if(c==’q’)
break;
}
}
}
|
程序执行后等待用户输入。如果用户输入程序就会把它打印到屏幕上。如果用户在3秒钟未输入任何字符,程序就打印“Time out!”.
本程序实现了一个文件描述符的非阻塞I/O。
分享到:
相关推荐
select函数详解
linux socket的select函数例子
利用select函数在linux环境下实现的一个聊天程序,满足要求: (1)用户默认出于广播模式,一个客户在其客户端发送消息,其他客户端用户全部都可以收到; (2)程序支持下列命令 /help:显示帮助信息 /quit:用户退出...
linux c语言 select函数的用法
Select函数实现原理分析Select函数实现原理分析Select函数实现原理分析Select函数实现原理分析
详细的解释了linux下的select函数,对非阻塞IO进行了不错的描述
linux 下select的C语言编程技术,对于多路IO口编程有帮助
linux select函数串口应用例子
linux c语言 select函数用法
串口发送接收数据程序,用select函数进行接收
利用select函数,实现了从terminal端输入数据,然后输出到指定的文件中,适合新手,如果有什么问题,欢迎在下面评论。
嵌入式linux中 功能:完成串口读写操作,这里设定从串口读取消息时使用select函数,发送消息的程序不需要使用select函数,只发送“hello”消息由接收端接收
linux下select和poll的用法,关于设备驱动程序中的select和poll函数的用法。
linux下的使用select作为基本框架的一个简单功能的并发服务器实现
linux中select()函数分析.pdf
首先看看select函数原型如下: 代码如下:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);参数说明:slect的第一个参数nfds为fdset集合中最大描述符值加1,...
基于Linux开发板的GPIO子系统,使用poll()函数监听io口的实时电平变化,使用示例: GpioApi ioTest = new GpioApi(this); ioTest->addOutIO(GpioApi::IO_C_0);//添加输出口 ioTest->addInIO(GpioApi::IO_G_11);//...
可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,...
linux 下 select 编程 我们知道 select 是IO 多路复用的一个最简单支持,poll 和 epoll 是 select 的升级版。在 UNIX 网络编程第五章读书笔记 我们遇到这样一个问题:当客户端阻塞在 fgets() 等待客户输入的时候,...
epoll在内核版本2.6以上才出现的新的函数,而他们在linux内核中的实现都是十分相似。 这三种函数都需要设备驱动提供poll回调函数,对于套接字而言,他们是 tcp_poll,udp_poll和datagram_poll; 对于自己开发的设备...