【问题标题】:Why does it take so long to send TCP packets to localhost?为什么将 TCP 数据包发送到 localhost 需要这么长时间?
【发布时间】:2014-02-27 02:18:13
【问题描述】:

我编写了一个简单的 C++ 客户端/服务器对。服务器只是在套接字接受上分叉一个进程,然后等待来自客户端的数据包,然后用另一个数据包响应。客户端只是向服务器发送一个数据包,然后等待回复。我在发送之前和接收之后的客户端中有计时码。

我在本地机器上同时运行服务器和客户端,并将客户端连接到本地主机。

在我的计时中,中位延迟似乎在 2 毫秒左右。鉴于我并没有真正在网络上发送任何东西。 2 毫秒的延迟对我来说似乎非常高。

谁能解释为什么我看到如此高的延迟,或者这个时间量对于环回地址是否现实?

我在 Linux Ubuntu 12.04 上。我直接使用 TCP 套接字系统调用而不是任何包装器(即接受、侦听、发送、接收)。

服务器主体:

while (1) 
{   
    ++msgNum;

    sin_size = sizeof their_addr; 
    new_fd = accept(sockfd, (struct sockaddr*) &their_addr, &sin_size);
    if (new_fd == -1) 
    {   
        perror("accept");
        continue; 
    }   

    inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr*) &their_addr), 
        s, sizeof s); 
    printf("server: got connection from %s\n", s); 

    if (!fork())
    {   
        close(sockfd); // child doesn't need the listener

        MyMsg msg;
        strcpy(msg.buf, "Hello world");

        for (int i = 1; i <= NUM_TEST_MSGS; ++i)
        {   
            msg.id = i;

            int numbytes = 0;
            int bytesRecv = 0;

            while (numbytes < MSG_LEN)
            {   
                int sendSize = MSG_LEN - numbytes;
                if ((bytesRecv = send(new_fd, ((char*) &msg) + numbytes, 
                        sendSize, 0)) == -1) 
                {   
                    perror("send");
                    exit(1);
                }   
                numbytes += bytesRecv;
            }   

            assert(numbytes == MSG_LEN);

            //printf("Server sent %d num bytes\n", numbytes);
        }   

        printf("Server finished sending msgs.\n");

        close(new_fd);
        exit(0);
    }   
    close(new_fd);
} 

客户端正文:

for (int i = 1; i <= NUM_TEST_MSGS; ++i)
{
    MyMsg msg;

    int numbytes = 0;
    int bytesRecv = 0;

    int start = rdTsc.Rdtsc();

    while (numbytes < MSG_LEN)
    {
        int recvSize = MSG_LEN - numbytes;
        if ((bytesRecv = recv(sockfd, ((char*) &msg) + numbytes, recvSize, 0)) == -1)
        {
            perror("recv");
            exit(1);
        }

        numbytes += bytesRecv;
    }

    int end = rdTsc.Rdtsc();

    perfCounter.Track(end - start);

    if (numbytes != MSG_LEN)
    {
        printf("COMP FAILED: %d %d\n", numbytes, MSG_LEN);
    }

    assert(numbytes == MSG_LEN);

    if (i != msg.id)
    {
        printf("Msg %d id %d \n", i, msg.id);
    }

    //if (numbytes != MSG_LEN) printf("GOT WEIRD SIZE %d\n", numbytes);
    assert(msg.id == i);

    //printf("client: received %d num bytes id %d body '%s'\n", numbytes, msg.id, msg.buf);

    if (i % 1000 == 0)
    {
        printf("Client: Received %d num msgs.\n", i);
    }
}

printf("Client: Finished successfully.\n");

close(sockfd);

【问题讨论】:

  • 如果您发布代码,我们可以为您提供更好的帮助。

标签: c++ performance tcp


【解决方案1】:

对于可能从未离开内核缓冲区的东西来说,2ms 确实听起来很高。我怀疑这实际上可能是用于时间戳的函数不准确。

【讨论】:

  • 我的时间戳使用 tsc 计数器而不是任何系统调用。我以前曾将这些计数器用于其他目的。所以我可以排除时间戳。
  • 消息有多大?一眼看不到任何明显的东西(重复 printf() 和/或不断打开/关闭),所以我现在开始考虑像 Linux 这样的真正投机性的东西,决定阻塞而不是增加缓冲区..
  • 没那么大。 1000 字节。会不会是唠叨?
  • 忘记了 - 尝试设置 IPPROTO_TCP TCP_NODELAY 看看会发生什么..
猜你喜欢
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
相关资源
最近更新 更多