日期:2014-05-16 浏览次数:20893 次
笔者在写程序的时候,发现了select方法真的是非常奇妙,当我们读某一个串口数据,并且要有超时机制的时候,用select方法就可以时间,或者也可以用time(NULL)来计时实现,我们今天只探讨用select方法。
我们来看看程序:
/*----------------------------------------- 函数名: serial_read 参数: int fd,char *str,unsigned int len,unsigned int timeout 返回值: 在规定的时间内读取数据,超时则退出,超时时间为ms级别 描述: 向fd描述符的串口接收数据,长度为len,存入str,timeout 为超时时间 *-----------------------------------------*/ int serial_read(int fd, char *str, unsigned int len, unsigned int timeout) { fd_set rfds; struct timeval tv; int ret; //每次读的结果 int sret; //select监控结果 int readlen = 0; //实际读到的字节数 char * ptr; ptr = str; //读指针,每次移动,因为实际读出的长度和传入参数可能存在差异 FD_ZERO(&rfds); //清除文件描述符集合 FD_SET(fd,&rfds); //将fd加入fds文件描述符,以待下面用select方法监听 /*传入的timeout是ms级别的单位,这里需要转换为struct timeval 结构的*/ tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout%1000)*1000; /*防止读数据长度超过缓冲区*/ //if(sizeof(&str) < len) // len = sizeof(str); /*开始读*/ while(readlen < len) { sret = select(fd+1,&rfds,NULL,NULL,&tv); //检测串口是否可读 if(sret == -1) //检测失败 { perror("select:"); break; } else if(sret > 0) //检测成功可读 { ret = read(fd,ptr,1); printf("sec: %d,usec: %d\n",tv.tv_sec,tv.tv_usec); if(ret < 0) { perror("read err:"); break; } else if(ret == 0) break; readlen += ret; //更新读的长度 ptr += ret; //更新读的位置 } else //超时 { printf("timeout!\n"); break; } } return readlen; }一目了然,计时从fd这个设备描述符读取数据,读入的数据存入str中,长度为len,超时时间为timeout。
这里大家一定会很奇怪,为什么我要一个个字节的读出数据?这个函数原来也不是笔者写的,是参照一个大牛的写法,我一开始也没明白,后来终于明白:因为要超时!
tv这个参数,会在记录调用了select后消耗的时间,这样当我每次while循环的时候,就可以检测并且记录tv还剩多少时间能让我消耗,若tv的值为0了,那么就是超时了。
打开串口,我们来看看运行结果:
可以看到我从串口输入了11个数据,每传入一个字节的数据大概耗时70us
(笔者输入的是i love you ,但是原先输入了多次i love you linux and unix and meego缓冲区没有清除,35个字节太长没有办法截图,谅解~~~)
如此就可以实现超时读数据,select方法原来还有这样用,我也是刚刚发现,和大家分享!