c - AF_UNIX 套接字开销?

标签 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字节)写入小消息时。我只能在写入 block 之前写入其中的 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

最佳答案

查看 socket(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.

因此,开销似乎只是为内核保存簿记信息。

关于c - AF_UNIX 套接字开销?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10899814/

相关文章:

c++ - 如何从 MPI 中的结构类型创建新的派生数据类型?

c - 为什么 scanf 不需要字符串的符号并且在 printf 中也能正常工作(在 C 中)?

c - 地址空间库或进程

Android - JavaPhoenixChannel - EPIPE(断管)

Java - 套接字 - 显示服务器上所有文件的名称

尝试分配空间时 Calloc 导致错误。 (实现虚拟磁盘)

regex - 如何使用 sed 在文件中创建此模式

linux - 更改 macOS 主目录名称后 vscode 'code' 命令仅用作 sudo

linux - 如何grep curl -I header信息

c - 对UDP套接字使用shutdown()