代码之家  ›  专栏  ›  技术社区  ›  Andrew Bainbridge

Winsock本地回圈延迟

  •  4
  • Andrew Bainbridge  · 技术社区  · 14 年前

    我使用tcp套接字在Windows XP上提供两个应用程序之间的进程间通信。我选择tcp套接字的原因有很多。我看到平均往返时间为2.8毫秒,比我预期的要慢得多。分析似乎表明,延迟介于一个应用程序调用s end和另一个应用程序阻塞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);
     }
    

    守护程序客户端套接字线程(侦听来自客户端的数据包):

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

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

    你知道为什么延迟这么差吗?我怀疑纳格尔的算法,但我的代码乱扔了:

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

    没用。我需要在客户端和守护进程套接字上都这样做吗(我正在做)?

    我在一台四核机器上,几乎没有负载,没有磁盘活动等等。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Len Holgate    14 年前

    首先,在服务器中,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循环)。

    有多少客户?有多少根线?

        2
  •  1
  •   user207421    14 年前

    如果您不介意绑定到Windows API,我将查看命名管道而不是套接字。