1

我正在编写一个小程序来测试网络吞吐量作为练习的一部分,并且需要将发送和接收缓冲区增加到 256 KB(以尝试提高 TCP 性能)。我正在使用setsockopt()SO_SNDBUF/SO_RCVBUF 选项执行此操作,并且还增加了 'net.core.rmem_max' 和 'net.core.wmem_max' 值。

getsockopt() 确认缓冲区大小的增加(256KB 值的两倍)所以我知道这很好。但是,当我将 256KB 的数据从一台主机发送到另一台主机时,接收器总是以多次读取的形式接收数据,每次读取的大小各不相同(形成 20 到 40 次读取,接收字节数从 1448 到 18824 不等),直到它接收到所有数据. 在这一点上我很困惑,主要是这些问题,

  1. 随着缓冲区大小的增加,它不应该在一次读取中接收它吗?
  2. 另外,为什么每次读取的字节数差异如此之大(它们不应该更不恒定)?
  3. 有什么方法可以确保一次读取就收到 256KB 吗?

下面是显示读取部分的接收端片段,

  while(1) {
    memset(&client_addr, 0, sizeof(client_addr));
    if ((connfd = accept(listenfd, (struct sockaddr*)&client_addr, &socklen)) <= 0) {
      perror("accept()");
      exit(EXIT_FAILURE);
    }

    while ((n = recv(connfd, &buff[0], BUFF_SIZE, 0/*MSG_WAITALL*/)) > 0) {
      totalBytes += n;
      ++pktCount;
      printf("Received(%d): %d bytes\n", pktCount, n);
    }

    if (n == 0) {
      printf("Connection closed (Total: %lu bytes received)\n", totalBytes);
    }

    close(connfd);
    connfd = -1;
    totalBytes = 0;
    pktCount = 0;
  }

任何帮助都会很棒。

TIA

4

2 回答 2

2

随着缓冲区大小的增加,它不应该在一次读取中接收它吗?

不是。TCP/IP 是一种流式传输协议,将数据分段为更小的数据包。缓冲区大小主要影响底层网络层实现可以使用多少内存(Linux 通常将您设置的内存加倍),但不能保证接收将接收与发送方发送数据完全相同大小的数据块(之后所有,当您调用时send()/write(),实际上并不意味着数据包已发送。此外,由于MTU ,您很可能无论如何都会拆分数据包。

另外,为什么每次读取的字节数差异如此之大(它们不应该更不恒定)?

您可能想调试为什么会发生这种情况。有数百个因素——使用的 NIC、它的设置、它的驱动程序、TCP/IP、TCP、以太网网络层设置、发送方和接收方之间的东西(即交换机)等。但是,嘿,当你的操作系统有更多数据进来时并且应用程序正在处理前一个块。鉴于将数据从 NIC 传递到用户空间应用程序的成本相对较高,因此数据被缓冲并且您​​获得不同大小的数据也就不足为奇了。

有什么方法可以确保一次读取就收到 256KB 吗?

可能有。人们可能会使用阻塞read()并要求操作系统仅在收到至少 256KB 或发生错误时才唤醒进程。

于 2012-11-24T17:30:37.253 回答
2

您将有大约 180 个数据包要发送,这远不及大量数据。Nagle将导致任意数量的数据包在发送和接收时被任一操作系统缓冲。

何时将呈现任何缓冲数据包的触发器recv()取决于实现。它很可能会在一定时间后或达到一定数量的内部缓冲区大小后呈现所有数据包。在某些操作系统上,您可以使用SO_RCVLOWAT套接字选项更改这些级别。

于 2012-11-24T17:30:44.823 回答