linux中select 方法延迟

首先搞清楚select的参数、返回值,代表些什么。

1、头文件   #include <sys/select.h> 

2、参数      函数原型:int select (int maxfd + 1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval * timeout);

参数一:最大的文件描述符加1。

参数二:用于检查可读性,

参数三:用于检查可写性,

参数四:用于检查带外数据

参数五:一个指向timeval结构的指针,用于决定select等待I/o的最长时间。如果为空将一直等待。timeval结构的定义:struct timeval{

long tv_sec; // seconds
long tv_usec; // microseconds
}
3、返回值

>0:就绪描述字的正数目

-1:出错
0 :超时
readset writeset exceptset指定我们要让内核测试读、写和异常条件的描述字。如果对某一个的条件不感兴趣,就可以把它设为NULL。如果三个指针都为NULL,我们就有了一个比sleep()函数更为精确的定时器(sleep()以毫秒为最小单位,这个以微秒为单位)。
以下是转载的一篇文章

我们来看看程序:

[cpp]  view plain copy
  1. /*----------------------------------------------------------------------------- 
  2.   函数名:      serial_read 
  3.   参数:        int fd,char *str,unsigned int len,unsigned int timeout 
  4.   返回值:      在规定的时间内读取数据,超时则退出,超时时间为ms级别 
  5.   描述:        向fd描述符的串口接收数据,长度为len,存入str,timeout 为超时时间 
  6.  *-----------------------------------------------------------------------------*/  
  7. int serial_read(int fd, char *str, unsigned int len, unsigned int timeout)  
  8. {  
  9.     fd_set rfds;  
  10.     struct timeval tv;  
  11.     int ret;                                //每次读的结果  
  12.     int sret;                               //select监控结果  
  13.     int readlen = 0;                        //实际读到的字节数  
  14.     char * ptr;  
  15.   
  16.     ptr = str;                          //读指针,每次移动,因为实际读出的长度和传入参数可能存在差异  
  17.   
  18.     FD_ZERO(&rfds);                     //清除文件描述符集合  
  19.     FD_SET(fd,&rfds);                   //将fd加入fds文件描述符,以待下面用select方法监听  
  20.   
  21.     /*传入的timeout是ms级别的单位,这里需要转换为struct timeval 结构的*/  
  22.     tv.tv_sec  = timeout / 1000;  
  23.     tv.tv_usec = (timeout%1000)*1000;  
  24.   
  25.     /*防止读数据长度超过缓冲区*/  
  26.     //if(sizeof(&str) < len)  
  27.     //  len = sizeof(str);  
  28.   
  29.   
  30.     /*开始读*/  
  31.     while(readlen < len)  
  32.     {  
  33.         sret = select(fd+1,&rfds,NULL,NULL,&tv);        //检测串口是否可读  
  34.   
  35.         if(sret == -1)                                      //检测失败  
  36.         {  
  37.             perror("select:");  
  38.             break;  
  39.         }  
  40.         else if(sret > 0)                                    //检测成功可读  
  41.         {  
  42.             ret = read(fd,ptr,1);  
  43.             printf("sec: %d,usec: %d\n",tv.tv_sec,tv.tv_usec);  
  44.             if(ret < 0)  
  45.             {  
  46.                 perror("read err:");  
  47.                 break;  
  48.             }  
  49.             else if(ret == 0)  
  50.                 break;  
  51.   
  52.             readlen += ret;                                 //更新读的长度  
  53.             ptr     += ret;                                 //更新读的位置  
  54.         }  
  55.         else                                                    //超时  
  56.         {  
  57.             printf("timeout!\n");  
  58.             break;  
  59.         }  
  60.     }  
  61.   
  62.     return readlen;  
  63. }  
一目了然,计时从fd这个设备描述符读取数据,读入的数据存入str中,长度为len,超时时间为timeout。

这里大家一定会很奇怪,为什么我要一个个字节的读出数据?这个函数原来也不是笔者写的,是参照一个大牛的写法,我一开始也没明白,后来终于明白:因为要超时!

tv这个参数,会在记录调用了select后消耗的时间,这样当我每次while循环的时候,就可以检测并且记录tv还剩多少时间能让我消耗,若tv的值为0了,那么就是超时了。

打开串口,我们来看看运行结果:

linux中select 方法延迟_第1张图片

可以看到我从串口输入了11个数据,每传入一个字节的数据大概耗时70us

(笔者输入的是i love you ,但是原先输入了多次i love you linux and unix and meego缓冲区没有清除,35个字节太长没有办法截图,谅解~~~)

如此就可以实现超时读数据,select方法原来还有这样用,我也是刚刚发现,和大家分享!



你可能感兴趣的:(linux中select 方法延迟)