Windows TCP套接字接收延迟

4
外部控制器通过TCP/IP套接字每30毫秒发送120字节的消息。应用程序通过标准的tcp/ip套接字recv函数接收这些消息。在Linux和OSX下完美运行(recv每30毫秒返回120字节的消息)。在Windows下,recv返回大约每1秒钟~3500个字节的缓冲区。其余时间返回0。在Windows下,Wireshark显示消息确实每30毫秒到来。
如何使Windows tcp socket正常工作(无延迟)?
PS:我已经尝试过TCP_NODELAY和TcpAckFrequency。 Wireshark显示一切正常。因此,我认为这是某种应该被关闭的Windows优化。
阅读--
int WMaster::DataRead(void)
{
if (!open_ok)  return 0;
if (!CheckSocket())
{
    PrintErrNo();
    return 0;
}
iResult = recv(ConnectSocket, (char *)input_buff,sizeof(input_buff),0);

nError=WSAGetLastError();
if(nError==0) return iResult;
if(nError==WSAEWOULDBLOCK) return iResult;

PrintErrNo();
return 0;
}

初始化-

ConnectSocket = INVALID_SOCKET;

iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&clientService, sizeof(clientService));
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( deviceName.toLatin1().constData() );
clientService.sin_port = htons( port);

iResult = setsockopt(ConnectSocket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, 
sizeof (int));

u_long iMode=1;
iResult=ioctlsocket(ConnectSocket,FIONBIO,&iMode);

iResult = ::connect( ConnectSocket, (SOCKADDR*) &clientService, 
sizeof(clientService) );

CheckSocket -

bool WMaster::CheckSocket(void)
{
socklen_t len = sizeof (int);
int retval = getsockopt (ConnectSocket, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len );
if (retval!=0)
{
   open_ok=false;
   return false;
};
return true;
}

我添加了套接字初始化(iResult解析被剥离)。 - question2013
1
另外,您正在运行什么类型的防火墙和互联网安全软件?这些可能会干扰套接字操作。检查已安装的Winsock LSP和非Microsoft的过滤驱动程序。如果有疑问,请在干净的机器上进行测试。 - selbie
我将其正式化为下面的答案。另外,你能把CheckSocket函数的代码发一下吗? - selbie
1
你可以尝试移除CheckSocket。它并没有做任何recv()调用的返回值和随后的WSAGetLastError无法推断出的事情。 - selbie
我移除了CheckSocket,只有在recv返回负值时才调用WSAGetLastError。没有结果。我在Win7上遇到了这个错误。一些WinXP机器可以完美地工作。 - question2013
显示剩余7条评论
2个回答

1
考虑禁用 Nagle 算法。120 字节相当小,可能会在发送之前缓冲数据。我认为另一个原因是 Nagle 算法,因为在 1 秒钟内应该发送约 33 次。这对应着 33*120 = 3960 bytes / sec,非常类似于你看到的 3500。

我认为可以通过TCP_NODELAY关闭Nable算法。我尝试过了,但没有结果。正如我所说的,Wireshark显示通信没有延迟。 - question2013
这是一个非常好的猜测,也可能是问题所在。但我认为Nagle算法只适用于发送方。也许它会影响接收方延迟ACK。 - selbie
发送端绝对没有Nagle。Linux和OSX应用程序(接收端)工作正常。Wireshark(Windows)在接收端告诉我们没有延迟。实际上,ACK影响了它,Wireshark显示了它。经过TcpAckFrequency的调整,200毫秒的延迟消失了。 - question2013
但问题仍然存在 - 消息每30毫秒(Wireshark)到来一次,recv大约每秒返回所有消息。 - question2013
我非常怀疑 Nagle 可能是一个可能的原因,它会延迟“发送”数据包,但 OP 已经通过 Wireshark 验证数据包每 30 毫秒“到达”。 - Damon
是的,我说过了。我认为Windows套接字进行了一些优化,并将非常小的消息累积在一个包中。问题是 - 如何关闭此优化。 - question2013

0
将您的dataread函数更改如下,以便仅在出现错误时调用WSAGetLastError。
int WMaster::DataRead(void)
{
  if (!open_ok)  return 0;
  if (!CheckSocket())
  {
      PrintErrNo();
      return 0;
  }
  iResult = recv(ConnectSocket, (char *)input_buff,sizeof(input_buff),0);
  if(iResult >= 0)
  {
      return iResult;
  }

  nError=WSAGetLastError();
  if(nError==WSAEWOULDBLOCK) return iResult;

   PrintErrNo();
   return 0;
}

你每毫秒轮询一次套接字可能与你的性能问题有关。但在得出这个问题之前,我想看一下 CheckSocket 的源代码。

我把CheckSocket放在了顶部。 - question2013
我已经检查了您的修复。结果相同。我尝试完全删除CheckSocket()-结果仍然相同。 - question2013

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接