Linux - 使用FIONREAD的ioctl始终为0

时间:2011-08-08 08:59:32

标签: sockets ioctl

我试图了解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函数时,我实际读取了一些有效数据(我预期的)

5 个答案:

答案 0 :(得分:11)

这种情况很快发生,这就是为什么你什么也看不见的原因。你在做什么:

  • ioctl:我有数据吗? 不,还没有
  • recv:阻止,直到有数据供我使用。一些(短)时间之后:这是您的数据

因此,如果您真的想看{4},请等待它。

FIONREAD

答案 1 :(得分:9)

这里真正的答案是使用像cnicutar所说的select(2)。托比,你不理解的是你有竞争条件。首先,您查看套接字并询问有多少字节。然后,当您的代码处理“此处没有数据”块时,硬件和硬件正在接收字节。 OS与您的应用程序异步。因此,在调用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不要读取比你可以存储在用户传入的缓冲区中更多的字节。然后你的函数接口变成“这个fn将返回尽可能多的字节数。 socket,但不超过[传入的缓冲区大小]“。

这意味着此功能不再需要担心清除缓冲区。调用者可以根据需要多次调用您的函数来清除其中的所有字节(或者您可以提供单独的fn来丢弃数据批发,而不是在任何特定数据收集功能中绑定该功能)。不做太多事情,你的功能更灵活。然后,您可以创建一个智能的包装函数,以满足特定应用程序的数据传输需求,并且fn根据特定应用程序的需要调用get_data fn和clear_socket fn。现在你正在建立一个图书馆,你可以从一个项目到另一个项目随处携带,如果你有一个雇主让你随身携带代码,那么就可以找工作。

答案 2 :(得分:3)

使用select()然后使用ioctl(FIONREAD)然后使用recv()

答案 3 :(得分:2)

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

答案 4 :(得分:0)

对于那些正在使用docker的用户,当我尝试使用tcpreplay将外部数据包(在这种情况下为Ubuntu 16.04)发送到docker接口(在这种情况下为docker0)时,我遇到了同样的问题。

解决方法是在docker内部运行tcpreplay。

我不知道docker是否支持ioctl(),所以这不是解决方案。