在Linux环境中,我有一个应用程序,它从API调用到驱动程序获取文件描述符。我使用以下函数来读取系统中卡读入的数据。大约十分之一的读取失败。我很困惑为什么,在成功选择之后,检查是否设置了read_fd,没有返回数据。
int MyClass::Read(int file_descriptor)
{
unsigned short read_buffer[READ_BUFFER_SIZE];
fd_set read_set;
time_val timeout;
int return_value = 0;
int count = 0;
int status = -1;
// Initialize read file descriptor
FD_ZERO(&read_set)
// Add driver file descriptor
FD_SET(file_descriptor, &read_set)
// Set timeout
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
while(!count)
{
// Wait for data to be available to read
return_value = select(file_descriptor + 1, &read_set, NULL, NULL, &timeout);
// Make sure an error or a timeout didn't occur
if (-1 == return_value)
{
cout << "an error occurred" << endl;
}
else if (0 == return_value)
{
cout << "a timeout occurred" << endl;
}
else
{
// If the read file descriptor is set, read in the data
if (FD_ISSET(file_descriptor, &read_set))
{
count = read(file_descriptor, read_buffer, sizeof(read_buffer));
// Double check that data was read in
if (!count)
{
cout << "read failed" << endl;
}
else
{
// Set status to success
status = 0;
}
}
}
}
return status;
}
答案 0 :(得分:1)
读取的返回值为0(您的if (!count)
检查)并不意味着读取失败 - 这意味着读取成功并获得了EOF。
在任何情况下,select
返回文件描述符集并不意味着读取该fd不会失败 - 这意味着读取该fd将不会阻塞,并将立即返回一些内容,无论是失败还是成功。
答案 1 :(得分:0)
您没有正确使用select()
。它修改了fd_set
,可能还修改了time_val
,所以你必须在每次循环迭代时重置它们。
此外,您没有正确处理错误。 read()
出错时返回-1,断开时返回0,&gt;读取字节数为0。您没有正确处理错误和断开条件。
尝试更像这样的东西:
int MyClass::Read(int file_descriptor)
{
unsigned short read_buffer[READ_BUFFER_SIZE];
fd_set read_set;
time_val timeout;
int return_value, count;
do
{
// Initialize read file descriptor
FD_ZERO(&read_set);
// Add driver file descriptor
FD_SET(file_descriptor, &read_set);
// Set timeout
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
// Wait for data to be available to read
return_value = select(file_descriptor + 1, &read_set, NULL, NULL, &timeout);
// Make sure an error or a timeout didn't occur
if (-1 == return_value)
{
cout << "select failed" << endl;
return -1;
}
if (0 == return_value)
{
cout << "select timed out" << endl;
continue; // or return, your choice...
}
// select() returned > 0, so the fd_set MUST be set,
// so no need to check it with FD_ISSET()...
// read in the data
count = read(file_descriptor, read_buffer, sizeof(read_buffer));
// Double check that data was actually read in
if (-1 == count)
{
cout << "read failed" << endl;
return -1;
}
if (0 == count)
{
cout << "peer disconnected" << endl;
return 0; // or -1, or whatever you want...
}
// success
break;
}
while (true);
return 0;
}