Linux -具有FIONREAD的ioctl始终为0

iyfamqjs  于 5个月前  发布在  Linux
关注(0)|答案(4)|浏览(77)

我想知道在我的TCP套接字上有多少字节是可读的。我用标志“FIONREAD”调用ioctl,它实际上应该给予我这个值。当我调用函数时,我得到的是返回值0(所以没有错误),但我的整数参数也得到了值0。这将是没有问题的,但当我调用recv()我实际上从套接字中读取了一些数据。我做错了什么?
//下面是一些代码:

char recBuffer[BUFFERLENGTH] = {0};
int bytesAv = 0;
int bytesRead = 0;
int flags = 0;
if ( ioctl (m_Socket,FIONREAD,&bytesAv) < 0 )
{
    // Error
}
if ( bytesAv < 1 )
{
    // No Data Available
}
bytesRead = recv(m_Socket,recBuffer,BUFFERLENGTH,flags);

字符串
当我调用recv函数时,我实际上读取了一些有效的数据(这是我所期望的)

sy5wg1nm

sy5wg1nm1#

它发生得非常快,这就是为什么你什么也看不见。你在做什么:

  • ioctl:有我的数据吗?* 没有,还没有 *
  • recv:阻塞,直到有数据给我。一些(短)时间后:* 这是您的数据 *

所以如果你真的想看FIONREAD,就等着吧。

/* Try FIONREAD until we get *something* or ioctl fails. */
while (!bytesAv && ioctl (m_Socket,FIONREAD,&bytesAv) >= 0)
    sleep(1);

字符串

vnzz0bqm

vnzz0bqm2#

这里的真实的答案是像cnicutar说的那样使用select(2)。Toby,你不明白的是你有一个竞争条件。首先你看一下套接字,并询问那里有多少字节。然后,当你的代码正在处理“这里没有数据”块时,字节正在被硬件和操作系统异步接收到你的应用程序。所以,当recv()函数被调用时,“没有字节可用”的答案不再为真...

if ( ioctl (m_Socket,FIONREAD,&bytesAv) < 0 )
{ // Error 
}

// BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!

if ( bytesAv < 1 ) // AND HERE!
{
    // No Data Available
    // BUT BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!
}

// AND MORE BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!

bytesRead = recv(m_Socket,recBuffer,BUFFERLENGTH,flags);
// AND NOW bytesRead IS NOT EQUAL TO 0!

字符串
当然,两年前的一个小睡眠可能修复了你的程序,但它也教会了你糟糕的编码实践,你失去了一个学习如何使用select()正确使用套接字的机会。
此外,正如Karoly Horvath所说,您可以告诉recv不要读取超过用户传入的缓冲区中可以存储的字节数。然后您的函数接口变为“This fn will return as many bytes as are available on the socket,but not more than [buffer size you passed in]"。
这意味着该函数不再需要担心清除缓冲区,调用者可以根据需要多次调用您的函数以清除其中的所有字节(或者,您可以提供一个单独的fn,该fn将大规模丢弃数据,而不将该功能绑定到任何特定的数据收集功能中)。你的函数不需要做太多的事情,因此更加灵活。然后你可以创建一个 Package 器函数,它可以智能地满足特定应用程序的数据传输需求,而这个fn会根据需要调用get_data fn和clear_socket fn。现在,你正在构建一个库,你可以从一个项目带到另一个项目,如果你很幸运,有一个雇主允许你随身携带代码的话,你还可以从一个工作带到另一个工作。

nbysray5

nbysray53#

使用select(),ioctl(FIONREAD),recv()

z0qdvdin

z0qdvdin4#

你没有做错什么,如果你使用阻塞I/O recv()将阻塞,直到数据可用。

相关问题