Заголовок сокета AF_UNIX?
Я вижу пару странных вещей с парой сокетов 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
2 ответа
Посмотрите на справочную страницу socket(7). Есть раздел, который гласит:
SO_SNDBUF Устанавливает или получает максимальный размер буфера отправки сокета в байтах. Ядро удваивает это значение (чтобы освободить место для накладных расходов на ведение бухгалтерского учета), когда оно установлено с помощью setsockopt(2), и это удвоенное значение возвращается getockopt(2). Значение по умолчанию задается файлом /proc/sys/net/core/wmem_default, а максимально допустимое значение задается файлом / proc / sys / net / core / wmem_max. Минимальное (удвоенное) значение для этой опции составляет 2048.
Таким образом, кажется, что накладные расходы - это просто хранение бухгалтерской информации для Ядра.
Вы смотрели на стоимость net.unix.max_dgram_qlen
SYSCTL?
Ядро накладывает ограничение на максимальное количество дейтаграмм AF_UNIX в полете. В моей системе ограничение на самом деле очень низкое: всего 10.