我想知道我的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);
Run Code Online (Sandbox Code Playgroud)
当我调用recv函数时,我实际读取了一些有效的数据(我预期的)
cni*_*tar 11
它发生得非常快,这就是为什么你什么也看不见.你在做什么:
ioctl:有数据吗?不,还没有recv:阻止,直到有数据给我.一些(短)时间之后:这是您的数据所以,如果你真的想看FIONREAD,只需等待它.
/* Try FIONREAD until we get *something* or ioctl fails. */
while (!bytesAv && ioctl (m_Socket,FIONREAD,&bytesAv) >= 0)
sleep(1);
Run Code Online (Sandbox Code Playgroud)
小智 9
这里真正的答案是使用像cnicutar这样的select(2).托比,你不理解的是你有竞争条件.首先,您查看套接字并询问有多少字节.然后,当您的代码正在处理"此处没有数据"块时,硬件和操作系统正在接收与您的应用程序异步的字节.因此,在调用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!
Run Code Online (Sandbox Code Playgroud)
当然,一个小小的睡眠可能在两年前修复了你的程序,但它也教会了你糟糕的编码练习,你失去了学习如何通过使用select()正确使用套接字的机会.
此外,正如Karoly Horvath所说,你可以告诉recv不要读取比你在用户传入的缓冲区中存储的更多的字节数.然后你的函数接口变成"这个fn将返回插槽上可用的字节数,但是不超过[传入的缓冲区大小]".
这意味着此功能不再需要担心清除缓冲区.调用者可以根据需要多次调用您的函数来清除其中的所有字节(或者您可以提供单独的fn来丢弃数据批发,而不是在任何特定数据收集功能中绑定该功能).不做太多事情,你的功能更灵活.然后,您可以创建一个智能的包装函数,以满足特定应用程序的数据传输需求,并且fn根据特定应用程序的需要调用get_data fn和clear_socket fn.现在你正在建立一个图书馆,你可以在项目之间随身携带,也许你可以找到工作,如果你很幸运,有一个雇主可以让你随身携带代码.