这里真正的答案是像 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!
当然,两年前的小睡眠可能修复了你的程序,但它也教会了你糟糕的编码练习,你失去了学习如何通过使用 select() 正确使用套接字的机会。
此外,正如 Karoly Horvath 所说,您可以告诉 recv 读取的字节数不要超过用户传入的缓冲区中存储的字节数。然后您的函数接口变为“此 fn 将返回套接字上可用的尽可能多的字节,但是不超过 [您传入的缓冲区大小]”。
这意味着此函数不再需要担心清除缓冲区。调用者可以根据需要多次调用您的函数以清除其中的所有字节(或者您可以提供一个单独的 fn 来丢弃数据批发并且不将该功能绑定在任何特定的数据收集函数中)。通过不做太多事情,您的功能更加灵活。然后,您可以创建一个对特定应用程序的数据传输需求智能的包装器函数,并且 fn 根据该特定应用程序的需要调用 get_data fn 和 clear_socket fn。现在,您正在构建一个库,您可以从一个项目到另一个项目,如果您有幸拥有一个可以让您随身携带代码的雇主,那么您可能会在另一个项目中随身携带。