Winsock本地环回延迟

时间:2010-10-12 14:48:15

标签: multithreading sockets winsock latency recv

我正在使用tcp套接字在Windows XP上的两个应用程序之间提供进程间通信。我出于各种原因选择了tcp套接字。我看到平均往返时间为2.8毫秒。这比我想象的要慢得多。分析似乎表明延迟是在一个应用程序调用发送和另一个端阻止recv返回之间。

我有应用程序,守护进程和客户端。它们的结构类似于伪代码:

守护程序线程1(侦听新连接):

while (1) {
   SOCKET listener_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   bind(listener_socket, (SOCKADDR*)&server_info, sizeof(SOCKADDR));
   listen(listener_socket, 1);
   SOCKET client_socket = accept(listener_socket, NULL, NULL);
   closesocket(listener_socket);
   CreateThread(client_thread);
 }

守护进程client_socket线程(侦听来自客户端的数据包):

char cmdBuf[256];
int cmdBufAmountData = 0;

while (1)
{   
    char recvBuf[128];
    int bytesTransferred = recv(m_clientSocket, recvBuf, sizeof(recvBuf), 0);

    // Copy received data into our accumulated command buffer (commands 
    // may be split across packet boundaries)
    memcpy(cmdBuf + cmdBufAmountData, recvBuf, bytesTransferred);
    cmdBufAmountData += bytesTransferred;

    // See if there is one or more complete commands in cmdBuf 
    // (commands are separated by '\0')
    while (commandExists(cmdBuf, cmdBufAmountData))
    {
        // do stuff with command
        send(m_clientSocket, outBuf, msgLen, 0);

        // Throw away the command we just processed by shuffling 
        // the contents of the command buffer left
        for (int i = 0; i < cmdBufAmountData - cmdLen; i++)
            cmdBuf[i] = cmdBuf[i + cmdLen];
        cmdBufAmountData -= cmdLen;
    }
}

客户端主题1:

start_timer();
send(foo);
recv(barBuf);
end_timer();       // Timer shows values from 0.7ms to 17ms. Average 2.8ms.

为什么延迟如此糟糕?我怀疑是Nagel的算法,但我的代码乱丢:

BOOL bOptVal = TRUE;
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&bOptVal, sizeof(BOOL));

没有帮助。我是否需要在客户端和守护进程套接字上执行此操作(我正在做)?

我使用的是四核机器,几乎没有负载,没有磁盘活动等。

2 个答案:

答案 0 :(得分:2)

首先,在你的服务器中,while循环应该在Accept而不是listen ...你只需要听一次,所以,更像是......

SOCKET listener_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(listener_socket, (SOCKADDR*)&server_info, sizeof(SOCKADDR));
listen(listener_socket, 1);
while (1) {
   SOCKET client_socket = accept(listener_socket, NULL, NULL);
   closesocket(listener_socket);
   CreateThread(client_thread);
 }

接下来,是的,如果要关闭nagle,则需要在接受的服务器套接字和连接的客户端套接字上执行此操作。您可以在连接/接受后立即执行此操作。所以,如果你只在一个套接字上设置nagle,那么这可能是你的问题。

鉴于您正在使用TCP,我假设您正在阅读,直到您有完整的消息,而不是假设一方发送==另一方发送一个recv。 (即我假设你的代码是缩写的,并没有显示正常的recv循环)。

有多少客户?有多少线程?

答案 1 :(得分:1)

在您想退出服务器之前,不应关闭侦听套接字。

如果您不介意使用Windows API,我会查看命名管道而不是套接字。