通过域套接字传输的单个数据包大小的实际限制是什么?

时间:2014-02-18 14:18:44

标签: linux sockets unix posix ipc

让我们假设为典型的服务器 - 客户端程序创建了一个Unix域套接字。客户端在套接字上发送10GB缓冲区,同时由服务器使用。

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

如果无法一次性发送域套接字的10GB缓冲区,那么单个数据包的实际大小限制是多少?

约束:

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

4 个答案:

答案 0 :(得分:27)

有许多因素会决定可以在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负载等)。

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

    实际数字取决于您的系统配置和使用情况。您需要通过测试确定限制...开始使用wmem_max(256Kb)和max_dgram_qlen(32)并保持加倍wmem_max直到您发现事情开始中断。您需要调整max_dgram_qlen以在一定程度上平衡生产者和消费者的活动(尽管如果生产者比消费者更快或更慢,则队列大小不会产生太大影响)。 / p>

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

    最佳猜测:实际限制将围绕wmem_max~8Mb和unix_dgram_qlen~32。

答案 1 :(得分:2)

域套接字本身没有“数据包”。 tcp“streams”或udp“datagrams”的语义是模拟的,内核看起来与用户空间应用程序类似,但就其本身而言。机制不像使用网络协议的网络套接字那样涉及。你真正感兴趣的是内核将为你缓冲多少。

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

或者,您可以查看sendfile

答案 2 :(得分:0)

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

答案 3 :(得分:-3)

如果您正在谈论SOCK_DGRAM,可以通过实验轻松确定。你在谈论SOCK_STREAM似乎更有可能,在这种情况下它根本无关紧要。 SOCK_STREAM会将它排在外面。只要写下你喜欢的任何大小的块:越大越好。