【问题标题】:What's the practical limit on the size of single packet transmitted over domain socket?通过域套接字传输的单个数据包大小的实际限制是多少?
【发布时间】:2014-03-18 08:50:45
【问题描述】:

让我们假设有一个为典型的服务器-客户端程序创建的 Unix 域套接字。客户端通过套接字发送一个 10GB 的缓冲区,同时被服务器消耗。

操作系统(Linux/BSD)是否将 10GB 缓冲区拆分为多个数据包并发送/使用它们,还是一次性发送?

如果不能一次性发送10GB的domain socket缓冲区,那么单个数据包的实际大小限制是多少?

约束:

  • 该程序将在 Linux 2.6.32+ 和 FreeBSD 9+ 上运行
  • 要发送的缓冲区大小范围从 3 字节到最大 10GB。

【问题讨论】:

  • 客户端一次性发送 10GB 缓冲区没有什么“典型”。通常,它会将一些源读入以 KB 而非 GB 为单位的缓冲区,然后逐块发送。
  • @EJP 你知道我需要分解多少 10GB 缓冲区吗?每 1GB/1MB?
  • 霍华德,你的插座是什么类型的?它是如何创建的以及如何发送|接收数据?
  • 这里好像回答了:stackoverflow.com/questions/4729315/…

标签: linux sockets unix posix ipc


【解决方案1】:

有许多因素将决定一个可以在 Unix 套接字上发送的数据包的最大大小:

  1. wmem_max 套接字发送缓冲区最大大小内核设置,它决定了可以使用setsockopt (SO_SNDBUF) 设置的发送缓冲区的最大大小。当前设置可以从/proc/sys/net/core/wmem_max 读取,并且可以使用sysctl net.core.wmem_max=VALUE 进行设置(将设置添加到/etc/sysctl.conf 以使更改在重新启动后保持不变)。请注意,此设置适用于所有套接字和套接字协议,而不仅仅是 Unix 套接字。

  2. 如果将多个数据包发送到 Unix 套接字(使用 SOCK_DATAGRAM),那么可以在不阻塞的情况下发送的最大数据量取决于套接字发送缓冲区的大小(见上文) Unix 套接字上的最大未读数据包数(内核参数net.unix.max_dgram_qlen)。

  3. 最后,数据包 (SOCK_DATAGRAM) 需要连续内存(根据 What is the max size of AF_UNIX datagram message that can be sent in linux?)。内核中有多少连续内存可用取决于许多因素(例如系统上的 I/O 负载等...)。

因此,为了最大限度地提高应用程序的性能,您需要较大的套接字缓冲区大小(以最大限度地减少由于套接字写入系统调用引起的用户/内核空间上下文切换)和较大的 Unix 套接字队列(将生产者和消费者解耦为尽可能)。但是,socket 发送缓冲区大小和队列长度的乘积不能太大,导致内核耗尽连续的内存区域(导致写入失败)。

实际数字取决于您的系统配置和使用情况。您需要通过测试来确定限制...从 256Kb 的 wmem_max 和 32 的 max_dgram_qlen 开始,然后继续加倍 wmem_max,直到您注意到事情开始破裂。您将需要调整max_dgram_qlen 以在一定程度上平衡生产者和消费者的活动(尽管如果生产者比消费者快得多或慢得多,队列大小不会有太大影响)。

请注意,您的生产者必须通过调用setsockopt (SO_SNDBUF) 将套接字发送缓冲区大小专门设置为wmem_max 字节,并且必须将数据拆分为wmem_max 字节块(消费者必须重新组装它们) .

最佳猜测:实际限制将在 wmem_max ~8Mb 和 unix_dgram_qlen ~32 左右。

【讨论】:

  • 你是对的。通过将缓冲区分成 128KB 的片段,我已经成功地通过域套接字传输了超过 1GB 的缓冲数据。非常感谢。
【解决方案2】:

域套接字本身没有“数据包”。 tcp“流”或 udp“数据报”的语义是在内核中模拟的,看起来类似于用户空间应用程序,但仅此而已。这些机制不像使用网络协议的网络套接字那样复杂。您真正感兴趣的是内核将为您缓冲多少。

从您的程序的角度来看,这并不重要。将套接字视为管道或 FIFO。当缓冲区填满时,您将阻塞;如果套接字是非阻塞的,您将获得短写入(假设流)或 EAGAIN 错误。无论缓冲区大小如何,这都是正确的。但是,您应该可以使用 getsockopt 查询缓冲区大小并使用 setsockopt 增加其大小,但我怀疑您是否会接近 10GB。

或者,您可以查看sendfile

【讨论】:

  • 谢谢,但我担心 sendfile 可能不适合我的用例 - 在我的用例中,缓冲区大小变化很大,范围从最低 3 字节到最高 10GB。
  • 由于您要发送到同一主机上的另一个程序,也许您宁愿只发送文件的路径(如果它是磁盘上的文件)并让其他程序读取它直接地;或者如果它是内存中的数据,也许使用 mmap() 以便其他程序可以直接从共享内存中读取它?
  • setsockopt 和 SO_SNDBUF 受限于 sysctl_wmem_max (wmem_max sysctl)
  • 这个答案是错误的。 Unix域套接字可以作为SOCK_DGRAM打开,保留写入之间的边界,每次读取对应一次写入。模拟与否,它是一个数据报,即使在名称上也是如此。
【解决方案3】:

这里有两个想法。一个是使用 SOCK_DGRAM 时发送的数据包的大小,另一个是域套接字的缓冲区大小。这取决于使用域套接字设置的变量。大小可能取决于它是否是内存文件套接字。

【讨论】:

    【解决方案4】:

    如果你说的是 SOCK_DGRAM,很容易通过实验确定。您似乎更有可能在谈论 SOCK_STREAM,在这种情况下,它根本无关紧要。 SOCK_STREAM 将在您的外部对其进行排序。写成你喜欢的任何大小的块:越大越好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-20
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      • 2019-11-16
      • 1970-01-01
      相关资源
      最近更新 更多