我看到一些奇怪的东西,一对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.
所以看起来,开销仅仅是为了保存内核的簿记信息。