AF_UNIX套接字开销?

时间:2012-06-05 15:04:07

标签: c linux sockets networking

我看到一些奇怪的事情,其中​​一对AF_UNIX套接字是通过以下呼叫创建的:

 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

使用管道确实有很多开销:

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

2 个答案:

答案 0 :(得分:6)

查看socket(7)手册页。有一节的内容如下:

  

SO_SNDBUF                 以字节为单位设置或获取最大套接字发送缓冲区。内核将此值加倍                 (当使用setsockopt(2)设置时,允许空间进行簿记开销)                 getsockopt(2)返回doubled值。默认值由。设置                 / proc / sys / net / core / wmem_default文件和最大允许值由                 / proc / sys / net / core / wmem_max文件。此选项的最小(加倍)值为                 2048。

所以看来,开销只是为了保存内核的簿记信息。

答案 1 :(得分:0)

您是否查看了net.unix.max_dgram_qlen sysctl的价值?

内核对飞行中AF_UNIX数据报的最大数量施加限制。 在我的系统上,限制实际上非常低:只有10。