1.select (看代码!! 解释看不懂)
头文件:#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
函数原型:int select (int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *tvptr);
返回值:准备就绪的描述符数,若超时则为0,若出错则为- 1 函数参数:
maxfd是需要监视的最大的文件描述符值+1;
中间三个参数readfds(可读文件描述符集)、writefds(可写文件描述符集)和exceptfds (异常条件描述符集)是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符。每个描述符集存放在一个fd_set数据类型中。
最后一个参数tvptr ,它指定愿意等待的时间。
struct timeval{ long tv_sec; /* seconds */
long tv_usec; /* and microseconds */ };
有三种情况: • tvptr == NULL:永远等待。如果捕捉到一个信号则中断此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回-1, errno设置为enter
• tvptr ->tv_sec == 0 && tvptr->tv_usec == 0:完全不等待。测试所有指定的描述符并立即返回。这是得到多个描述符的状态而不阻塞select函数的轮询方法。
• tvptr ->tv_sec != 0 && tvptr->tv_usec != 0 :等待指定的秒数和微秒数。当指定的描述符之一已准备好,或当指定的时间值已经超过时立即返回。如果在超时时还没有一个描述符准备好,则返回值是0,(如果系统不提供微秒分辨率,则tvptr->tv_usec值取整到最近的支持值。)与第一种情况一样,这种等待可被捕捉到的信号中断。
2.下面的宏提供了处理fd_set中的这三种描述词组的方式:
FD_CLR(int fd,fd_set* set);用来清除描述词组set中相关fd位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd位
FD_ZERO(fd_set *set)
用来清除描述词组set的全部位 以下列方式说明了一个描述符集后:
fd_set rset; int fd;
必须用F D Z E R O清除其所有位:
FD_ZERO (&rset); 然后在其中设置我们关心的各位:
FD_SET (fd,&rset);
FD_SET (STDIN_FILENO,&rset);
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
(1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。
(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。
注意:没有事件发生的fd=5被清空。
select有三个可能的返回值。
(1) 返回值-1表示出错。这是可能发生的,例如在所指定的描述符都没有准备好时捕捉到一个信号。
(2) 返回值0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超过,则发生这种情况。
(3) 返回一个正值说明了已经准备好的描述符数,在这种情况下,三个描述符集中仍旧打开的位是对应于已准备好的描述符位。
使用select的常见错误
1.当使用select时,1个最常见的编程错误是:忘了对最大描述字加1
2.忘了描述字集是值-结果参数,select返回时会将那些没准备好的bit置为0,所以如果要再次select时,一定要重新用FD_SET设置你感兴趣的描述字的对应bit
3.忘记重新填写timeout的值
3. select 代码:
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<sys/select.h>
//目标:使用select监控 标准输入设备。
//参数1:所有描述符+1
//参数2:输入描述符集合
//参数3:输出描述符集合
//参数4:异常错误描述符集合
//参数5:超时时间设定
//返回值:已经准备好的描述符个数。如果没有 : 0 如果错误 -1;
//1.监控一个集合中的所有描述符。哪个描述符有动态,立即做出应答。描述符代表文件。
//2.操作时间到了也会做出反应。
//3.调用select会阻塞当前任务。
//结束select阻塞状态的原因:1,有描述符准备好了,2超时时间到。
//select函数结束时,都会清空时间结构体,三个描述符集合(只会剩下已经准备好的描述符):
//每调用一次select,都要重新填写超时时间+描述符。
//select基本用法
int main()
{
fd_set rset = {0} ; //这个是描述符集合,把所有描述符放在这里面。
struct timeval tm = {0} ; //设定超时时间
int len = 0 ; //读到的长度
char buff[128] = ""; //读到的内容
int count = 0 ;
while(strncmp(buff,"quit",4))
{
//把键盘文件添加到描述符号集合中
FD_SET(STDIN_FILENO,&rset);
tm.tv_sec =3; //设定超时时间,如果3s内没有动静,就立刻返回
count = select(STDIN_FILENO + 1,&rset,NULL,NULL,&tm);
//有描述符准备好了。
printf("count is :%d\n",count);
//可以监控这个文件描述符号集合中有几个有回应 有没有准备好。
if(FD_ISSET(STDIN_FILENO,&rset))
{
fgets(buff,sizeof(buff),stdin);
printf("readlen is %s\n",buff);
}
}
return 0 ;
}
4.poll 函数
#include <poll.h>
原型 : int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:fds struct pollfd 类型的数据
nfds:说明fdarray数组中的元素数。
timeout:超时时间。若timeout==-1,则永远等待;若timeout==0,则不等待;若timeout>0,则等待timeout毫秒。 返回值:与select同。
poll提供了与select相似的功能,但当涉及到流设备时,它还提供附加信息。 #include <sys/poll.h> struct pollfd { int fd; / * 要检查状态的描述字 * /
short int events; / * 对于该描述字感兴趣的事件 * /
short int revents; / * 返回时,指出在该描述字上发生了什么事件 * / };
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<sys/select.h>
#include <poll.h>
int main()
{
//定义一个POLL结构体数组,一个成员
struct pollfd pfds[1] = {1};
//监控标准输入设备
pfds[0].fd = STDIN_FILENO;
//输入事件
pfds[0].events = POLLIN;
char buff[20] = "";
int count = 0 ;
while(1)
{
//描述符 数组 + 要监控的个数 +超时时间
count = poll(pfds,1,3000);//毫秒单位
printf("count is %d\n",count);
//结果事件是输入事件
if(pfds[0].revents == POLLIN)
{
bzero(buff,sizeof(buff));
fgets(buff,sizeof(buff),stdin);
printf("buff = %s\n",buff);
count = 0 ;
printf("count is %d\n",count);
}
}
return 0 ;
}