我看到有一对AF_UNIX套接字通过调用创build一对奇怪的东西,例如:
socketpair(AF_UNIX, SOCK_STREAM, 0, sfd);
其中sfd是文件描述符的int [2]数组。
首先,默认缓冲区大小似乎是122K(124928字节),而不是来自/ proc / sys / net的任何内容(例如设置为128K的wmem_default)。 有谁知道这个奇怪的缓冲区大小的原因?
其次,通过套接字(8字节)写小信息。 在写块之前我只能写423个字节,只有8 * 423 = 3384个字节,还有一个奇怪的大小。 这些消息就好像它们每个都占用了295+个小字节。 这种开销的来源是什么?
在RHEL6上运行(2.6.32,64位)
我编写了一个程序来尝试不同大小的数据来比较开销成本:
#include <errno.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define DATA_SIZE 4 void run(size_t size) { int sfd[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { perror("error"); } int sndbuf, sbsize = sizeof(sndbuf); getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); printf("Data Size: %zd\n", size); char buff[size]; size_t wrote=0; for (size_t ii=0; ii < 32768; ii++) { if ((send(sfd[0], buff, size, MSG_DONTWAIT) == -1) && (errno == EAGAIN)) { wrote = ii; break; } } printf("Wrote: %zd\n", wrote); if (wrote != 0) { int bpm = sndbuf/wrote; int oh = bpm - size; printf("Bytes/msg: %i\n", bpm); printf("Overhead: %i\n", oh); printf("\n"); } close(sfd[0]); close(sfd[1]); } int main() { int sfd[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); int sndbuf, sbsize = sizeof(sndbuf); getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); printf("Buffer Size: %i\n\n", sndbuf); close(sfd[0]); close(sfd[1]); for (size_t ii=4; ii <= 4096; ii *= 2) { run(ii); } }
这使:
Buffer Size: 124928 Data Size: 4 Wrote: 423 Bytes/msg: 295 Overhead: 291 Data Size: 8 Wrote: 423 Bytes/msg: 295 Overhead: 287 Data Size: 16 Wrote: 423 Bytes/msg: 295 Overhead: 279 Data Size: 32 Wrote: 423 Bytes/msg: 295 Overhead: 263 Data Size: 64 Wrote: 423 Bytes/msg: 295 Overhead: 231 Data Size: 128 Wrote: 348 Bytes/msg: 358 Overhead: 230 Data Size: 256 Wrote: 256 Bytes/msg: 488 Overhead: 232 Data Size: 512 Wrote: 168 Bytes/msg: 743 Overhead: 231 Data Size: 1024 Wrote: 100 Bytes/msg: 1249 Overhead: 225 Data Size: 2048 Wrote: 55 Bytes/msg: 2271 Overhead: 223 Data Size: 4096 Wrote: 29 Bytes/msg: 4307 Overhead: 211
与使用pipe道相比,这肯定有很多开销:
Data Size: 4 Wrote: 16384 Bytes/msg: 4 Overhead: 0 Data Size: 8 Wrote: 8192 Bytes/msg: 8 Overhead: 0 Data Size: 16 Wrote: 4096 Bytes/msg: 16 Overhead: 0 Data Size: 32 Wrote: 2048 Bytes/msg: 32 Overhead: 0 Data Size: 64 Wrote: 1024 Bytes/msg: 64 Overhead: 0 Data Size: 128 Wrote: 512 Bytes/msg: 128 Overhead: 0 Data Size: 256 Wrote: 256 Bytes/msg: 256 Overhead: 0 Data Size: 512 Wrote: 128 Bytes/msg: 512 Overhead: 0 Data Size: 1024 Wrote: 64 Bytes/msg: 1024 Overhead: 0 Data Size: 2048 Wrote: 32 Bytes/msg: 2048 Overhead: 0 Data Size: 4096 Wrote: 16 Bytes/msg: 4096 Overhead: 0
看看插座(7)手册页。 有一部分内容如下:
SO_SNDBUF设置或获取以字节为单位的最大套接字发送缓冲区。 当使用setsockopt(2)设置内核时,内核将此值加倍(以允许空间用于簿记开销),并且getsockopt(2)返回此加倍的值。 缺省值由/ proc / sys / net / core / wmem_default文件设置,最大允许值由/ proc / sys / net / core / wmem_max文件设置。 该选项的最小值(加倍)是2048。
所以看起来开销只是为内核保存簿记信息。
你看过net.unix.max_dgram_qlen
sysctl的值吗?
内核对正在进行的AF_UNIX数据报的最大数量施加了限制。 在我的系统上,极限实际上是非常低的:只有10。