Вопрос по sockets, linux, c – Заголовок сокета AF_UNIX?

20

Я вижу пару странных вещей с парой сокетов AF_UNIX, созданных вызовом, таких как:

 socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

Где sfd - массив int [2] для файловых дескрипторов.

Во-первых, размер буфера по умолчанию кажется равным 122 КБ (124928 байт), а не что-либо из / proc / sys / net (например, wmem_default, для которого установлено 128 КБ). Кто-нибудь знает причину этого странного размера буфера?

Во-вторых, при написании небольших сообщений через сокет (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
send () возвращает количество фактически записанных байтов. Вы должны суммировать их, а не просто предполагая, что все было написано. user207421
В худшем случае я напишу меньше, чем я утверждаю, что еще больше ухудшит издержки на сокете домена. Sean McAllister

Ваш Ответ

2   ответа
0

Вы смотрели на стоимостьnet.unix.max_dgram_qlen SYSCTL?

Ядро накладывает ограничение на максимальное количество дейтаграмм AF_UNIX в полете. В моей системе ограничение на самом деле очень низкое: всего 10.

Я не знал об этом, нет. Будет ли это применяться здесь, поскольку я пою тип SOCK_STREAM? Sean McAllister
Я могу сказать, что увеличениеnet.unix.max_dgram_qlen не изменяет накладные расходы. Моя система имеет значение по умолчанию 10, я изменяю его на 200 без каких-либо изменений в выходных данных программ или вычисленных накладных расходах.
Нет, это должно относиться только к сокетам дейтаграмм, по крайней мере, в версии ядра, которую я рассматриваю.
На самом деле, я не могу понять, почему запись в сокет датаграмм unix будет когда-либо короткой, если нажать wmem_max.
Не так много, как не в этом дело. Тем не менее, вы правы. Пожалуйста, прекратите голосование против меня;)
6

Посмотрите на справочную страницу 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.

Таким образом, кажется, что накладные расходы - это просто хранение бухгалтерской информации для ядра.

Я даже не уверен, что это применимо к локальным сокетам, и простая половина доступного буферного пространства по-прежнему не будет учитывать все накладные расходы, которые я вижу. Sean McAllister
Страница man не различает AF_UNIX или нелокальные домены, поэтому я предполагаю, что она применяется по всем направлениям. Это вся документация, которую я смог найти относительно ситуации. Я подозреваю, что если вам нужно знать "точно" Что за накладные расходы используются, вам нужно взглянуть на сетевой код ядра.
Я не принял этот ответ, потому что думаю, что даже с учетом накладных факторов, равных двум, я все еще вижу слишком много для каждого сообщения. Даже если бы ядро позволяло мне использовать только 62464 байта, я мог бы написать более 15000 сообщений перед заполнением буфера, и я вижу только 1/30 этого. Sean McAllister
Вам нужно будет прочитать сетевой код ядра, чтобы получить все детали того, что делается с накладными расходами, как я упоминал ранее. Я просто указываю, что страницы руководства говорят о накладных расходах.

Похожие вопросы