日期:2014-05-16  浏览次数:20629 次

菜鸟提问:关于read函数的问题
在linux下用串口接收数据的时候,采用read函数读取串口数据,但是一进入read的循环,程序总是停在那里,跳不出来.不知道为什么.
程序如下: 
void readshort(int fd)  
{
  unsigned int n=5000;  
  int nread;
  char buff[512];
  while (n) //循环读取数据
  {
  printf("start to read data\n");
  while((nread = read(fd, buff, 512))>0)
  { 
  // printf("\tLen %d",nread); 
  buff[nread] = '\0';  
  printf( "%s", buff); 
  }
  n--;
  } 
  printf("readshort completed");
}

程序执行到这个循环语句的时候,总是跳不出来.是不是我把要读的字节设成512太大了?因为串口那边的数据肯定是小于512的,理论上串口没有数据发过来的时候应该是可以结束读取的呀.

------解决方案--------------------
read函数默认是阻塞的.
ioctl(fd, FIONREAD, &status);
if(status>0)
nread = read(fd, buff, status))

或则用select来控制超时.
------解决方案--------------------
INT32 ReadComPort (INT32 ComPort, void *data, INT32 datalength)
{
INT32 retval = 0;
static fs_read;
FD_ZERO (&fs_read);
FD_SET (fd[ComPort], &fs_read);
tv_timeout.tv_sec = 0;//TIMEOUT_SEC (datalength, GetBaudrate ());
tv_timeout.tv_usec = 150000;//TIMEOUT_USEC;

retval = select (fd[ComPort] + 1, &fs_read, NULL, NULL, &tv_timeout);
if (retval)
return (read (fd[ComPort], data, datalength));
else
return (-1);
}

------解决方案--------------------
tv_timeout.tv_sec:单位是秒
tv_timeout.tv_usec单位是百万分之一秒

合在一起就是表示总的时间
------解决方案--------------------
我曾写过一篇文章介绍过select,想了解的话请参考:select函数与I/O多路转接 
http://blog.csdn.net/linyt/archive/2007/08/02/1722445.aspx

此外,也可以把它设为非阻塞的,代码如下:
void set_fl(int fd, int flags)
...{
int val;
//获取属性
if((val = fcntl(fd, F_GETFL, 0)) < 0)
...{
printf("get socket property error ");
exit(0);
}
//更改属性
val = val |flags;
//更改属性后再设置,以使它使效
if(fcntl(fd, F_SETFL, val) < 0)
...{
printf("set socket property error ");
exit(1);
}
}

set_fl(fd, O_NONBLOCK);

参见:http://blog.csdn.net/linyt/archive/2007/08/10/1736624.aspx

 while((nread = read(fd, buff, 512)) >0) 
关于这个代码,如果fd是阻塞的,那么它会阻塞直到有数据来,其中len返回的是数据的个数,小于等于512;并不是要读到512个数据才返回的,只要有数据,那么它就会返回。
如果fd是非阻塞的,如果有数据到数,它会反回读到的数据个数,而没有的时候,它马上返回-1表示没有数据准备好!