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



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

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

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

限制条件:

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

有许多因素将决定在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)需要连续内存(根据linux中可以发送的AF_UNIX数据报消息的最大大小是多少?)。内核中有多少连续内存将取决于许多因素(例如系统上的I/O负载等)

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

实际数字将取决于您的系统配置和使用情况。您需要通过测试来确定限制。。。从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左右。

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

从你的程序的角度来看,这其实并不重要。将套接字想象为管道或FIFO。当缓冲区填满时,你将被阻塞;如果套接字是非阻塞的,那么EAGAIN会出现短写(假设流)或错误。无论缓冲区的大小如何,这都是正确的。然而,您应该能够用getsockopt查询缓冲区大小,并用setsockopt增加其大小,但我怀疑您是否能接近10GB。

或者,您可以查看sendfile

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

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

相关内容

最新更新