我看到一些奇怪的东西,一对AF_UNIX插座创建的呼叫,如:
socketpair(AF_UNIX,SOCK_STREAM,sfd);
其中sfd是文件描述符的int [2]数组。
首先,默认缓冲区大小似乎是122K(124928字节),而不是/ proc / sys / net(如wmem_default,设置为128K)的任何东西。有没有人知道这个奇怪的缓冲区大小的原因?
第二,当通过套接字写入小消息(8字节)时。我只能在写入块之前写入其中的423个,这只有8 * 423 = 3384字节,另一个奇数的大小。这些消息的作用就好像它们每个占用了一点点字节一样。这个开销的来源是什么?
在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,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,sfd); int 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
与管道相比,绝对有很多开销:
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
Sets or gets the maximum socket send buffer in bytes. The kernel doubles this value
(to allow space for bookkeeping overhead) when it is set using setsockopt(2),and this
doubled value is returned by getsockopt(2). The default value is set by the
/proc/sys/net/core/wmem_default file and the maximum allowed value is set by the
/proc/sys/net/core/wmem_max file. The minimum (doubled) value for this option is
2048.
所以看起来,开销仅仅是为了保存内核的簿记信息。