2013-03-08 76 views
0

我有一个在Windows XP平台(i7 2.1 Ghz处理器)上运行的应用程序。此应用程序是通过UDP在主节点和从节点之间进行基于主/从的通信。 主站发送请求,从站节点在其响应(突发模式)中发送每5毫秒的数据包,每个数据包包括标头1300字节。Winsock函数的执行时间太长

回到主节点,主线程接收数据并将其写入队列,触发并行线程从线程读出。

问题: 读取下一个数据包时,Winsock API的执行时间很长,所以数据正在从缓冲区中丢失。

执行时间:Recvfrom() - 200 - 400微秒。

Open_Sock() 
{ 
    socket(); 
    //Error check 

    connect(); 
    //Error Check 
} 

Receivethread() 
{ 
    sock again: 

    select(socket, read,write,excep,(0,0)); 
    //error check 

    rc = recvfrom(socket,buf,len,0,&s_addr,&cln_alen) 
    if(rc>0) { 
     enqueue(queue,buf); 
    } 
} 

我确信Winsock API不需要很长时间才能获取下一个数据包。 但我找不到任何有关真实执行时间的信息。任何方向的帮助真的很感激。

+1

使用IOCP,排队大量缓冲区,让内核填满他们的。稍后处理它们。 – 2013-03-08 15:41:27

+0

能够为每个发送缓冲区调用recvfrom至少12.5次似乎应该足够充分(5ms/400us = 12.5)。你确定你正在处理的数据很快就完成了吗?另外,我们发现Windows倾向于丢弃比我们认为的更多的UDP数据包。我们将一个客户端/服务器Windows应用程序移植到Linux上,并使用相同的硬件丢弃了零个数据包。 – 2013-03-08 18:28:23

+0

默认情况下,套接字以阻塞模式运行,所以'recvfrom()'将在退出之前等待数据到达。既然你使用'select()',那么在你调用'recvfrom()'之前,套接字是否处于可读状态呢?知道套接字处于阻塞模式,除非你的线程在等待数据时需要做其他线程,否则你也可以放弃select()。 – 2013-03-08 20:21:27

回答

0

您可能遇到了发送/接收缓冲区大小和OS调度程序问题的组合。在Windows线程之间的平台上下文切换是不是太频繁,所以有两个选择,你可以使用:

  1. 服务器进程的增加优先

    这将减少时间您的服务器应用程序留在队列。

  2. 增加接收缓冲区大小

    你需要做的两端。您可以使用setsockopt的SO_RCVBUF选项:

    int size = 1 * 1024 * 1024; 
    setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const char*)&size, sizeof(int)); 
    
+0

谢谢你的建议。有用...!!!然而,不是从套接字读取垃圾的新的失败。 – 2013-03-13 15:05:56

+0

@Pipa然后打开一张新票:)并且不要忘记提供更多信息。 – 2013-03-13 16:05:38

0

如果丢失数据包是个问题,请使用TCP。使用TCP,对于简单的环回连接,我在不太现代的机器上实现了小于1毫秒的响应时间。这里有一些重要的点:

  • 当等待流量时,使用WSAEventSelect()和WaitForMultipleObjects()。我不确定这是否与select()相比有很大的不同,但是如果您想通过额外的事件停止线程,它会使处理更轻松。
  • 在等待输入之前分配一个缓冲区,这样会减少延迟。
  • 尝试不为每个数据包创建一个线程,但已经有线程等待,即使用线程池。
  • 尝试发送尽可能少的数据包,即尝试将整个数据组合在内存中并通过一次调用发送。这可避免稍后汇编的多个数据包的网络IO开销。
  • 另请参阅Nagle算法,您可能需要关闭TCP。 Nagle算法结合延迟确认可严重影响您的延迟。
+0

我不能切换到TCP,因为从站只能通过UDP进行通信。 而使用等待增加了延迟,我需要加速从缓冲区读取,因为奴隶处于突发模式。而且我无法控制从节点的触发,因为它是一个在ECU(从站)上运行的汽车应用。 – 2013-03-09 09:03:40