2013-03-23 176 views
4

外部控制器每30ms通过TCP/IP套接字发送120个字节的消息。 应用程序通过标准的tcp/ip套接字recv函数接收此消息。 它在Linux下完美工作& OSX(recv每30ms返回120字节的消息)。 在Windows下recv大约每1秒返回〜3500字节的缓冲区。其余时间返回0. Windows下的Wireshark显示消息确实每隔30ms进入一次。Windows TCP套接字接收延迟

如何使Windows的TCP套接字正常工作(没有延迟)?

PS:我已经玩过TCP_NODELAY & TcpAckFrequency了。 Wireshark显示一切正常。所以我认为这是一些Windows优化,应该关闭。

Reading--

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; 
} 

Initialization-

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; 
} 
+0

这很奇怪。你是否在这个套接字上设置了其他套接字选项?想到SO_RCVLOWAT,但在Windows上记录为不支持。另外,你说recv()在剩下的时间里“返回0”。如果套接字被远程端关闭,recv()将只返回0 - 即使套接字被设置为非阻塞。你能发布显示你如何创建和初始化套接字的代码吗? – selbie 2013-03-23 17:10:34

+0

我添加套接字初始化(iResult解析被剥离) – question2013 2013-03-24 21:22:07

+0

你可以分享你的代码,“调用recv”循环“?你的套接字是非阻塞的,并且你没有显示调用select或等待数据到达的代码。此外,如果recv()返回SOCKET_ERROR,则应该只调用WSAGetLastError。无法保证recv会在成功调用时将错误状态重新设置为0。 – selbie 2013-03-25 03:52:41

回答

1

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

+0

我想Nable alghorithm可以用TCP_NODELAY关闭。我玩它 - 没有结果。正如我所说 - wireshark显示沟通毫不拖延。 – question2013 2013-03-23 16:25:26

+0

这是一个非常好的猜测,可能是问题所在。但是我想图Nagle算法只适用于发送方。也许它会影响接收器延迟的ACK。 – selbie 2013-03-23 17:15:02

+0

发送方确定没有Nagle。 Linux和OSX应用程序(接收端)工作正常。接收方的Wireshark(Windows)告诉我们没有延迟。其实有ACK的影响,wireshark显示它。玩过TcpAckFrequency后200ms的延迟消失了。 – question2013 2013-03-23 22:49:50

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的来源之前将其作为问题。

+0

我把CheckSocket放在顶部 – question2013 2013-03-25 18:32:51

+0

我检查了你的修复。结果相同。我试图删除CheckSocket() - 完全一样。 – question2013 2013-03-26 00:12:49