Каков максимальный размер сообщения дейтаграммы AF_UNIX в Linux?

В настоящее время я достиг жесткого предела в 130688 байт. Если я попытаюсь отправить что-то большее в одном сообщении, я получу ошибку ENOBUFS.

Я проверил параметры net.core.rmem_default, net.core.wmem_default, net.core.rmem_max, net.core.wmem_max и net.unix.max_dgram_qlen sysctl и увеличил их все, но они не имеют никакого эффекта, потому что они относятся к общему размеру буфера, а не к размеру сообщения.

Я также установил параметры сокета SO_SNDBUF и SO_RCVBUF, но это имеет ту же проблему, что и выше. В любом случае размер буфера сокета по умолчанию устанавливается на основе параметров сокета по умолчанию.

Я просмотрел исходный код ядра, где ENOBUFS возвращается в стеке сокетов, но мне было непонятно, откуда он взялся. Единственные места, которые, похоже, возвращают эту ошибку, связаны с невозможностью выделить память.

Максимальный размер на самом деле 130688? Если нет, можно ли это изменить без перекомпиляции ядра?


person Jaime    schedule 18.01.2011    source источник
comment
Это огромная дейтаграмма. На мой взгляд, к тому времени, когда у вас будет такая большая дейтаграмма, вы уже можете использовать TCP.   -  person Jon Trauntvein    schedule 19.01.2011
comment
Да, это не помогает. Как я уже говорил в посте, это не позволит вам отправить сообщение с номером 130688 независимо от ваших настроек wmem. У меня они больше 32 МБ, и я пробовал много комбинаций ниже этого.   -  person Jaime    schedule 19.01.2011
comment
Просто чтобы добавить к этому. Это заблуждение, что буферы отправки и буферы приема предназначены для одиночных сообщений. Буфер — это общий буфер ядра для всех сообщений. Параметры wmem и qlen sysctl на самом деле влияют на то, как и когда отправлять блоки. По мере заполнения буфера отправки (при условии, что никто не получает), когда общее количество байтов в буфере превысит размер буфера или общее количество превысит qlen, отправка будет заблокирована.   -  person Jaime    schedule 19.01.2011
comment
Я лучше понял вашу точку зрения (и вопрос). Отредактировал запутанный комментарий и проголосовал за него; буду исследовать, как только позволит время, так как меня тоже интересует ответ.   -  person JB.    schedule 19.01.2011
comment
Это 128 КБ минус некоторые накладные расходы (384 байта). Это звучит вполне разумно для меня как максимальный размер сообщения. Если бы вы использовали внешний интерфейс, предел был бы намного ниже.   -  person Donal Fellows    schedule 19.01.2011
comment
Я согласен, что возможно, это жесткий предел. Просто пытаюсь найти какое-то доказательство и, возможно, какое-то обоснование этого.   -  person Jaime    schedule 19.01.2011


Ответы (1)


Дейтаграммам AF_UNIX SOCK_DATAGRAM/SOCK_SEQPACKET требуется непрерывная память. Трудно найти непрерывную физическую память, и выделение не удается, что-то похожее регистрируется в журнале ядра:

udgc: page allocation failure. order:7, mode:0x44d0
[...snip...]
DMA: 185*4kB 69*8kB 34*16kB 27*32kB 11*64kB 1*128kB 1*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3788kB
Normal: 13*4kB 6*8kB 100*16kB 62*32kB 24*64kB 10*128kB 0*256kB 1*512kB 0*1024kB 0*2048kB 0*4096kB = 7012kB
[...snip...]

unix_dgram_sendmsg() вызывает sock_alloc_send_skb() lxr1, который вызывает sock_alloc_send_pskb() с data_len = 0 и header_len = размер дейтаграммы lxr2. sock_alloc_send_pskb() выделяет header_len из «обычного» буферного пространства skbuff и data_len из страниц разброса/сбора lxr3. Итак, похоже, что сокеты AF_UNIX не поддерживают разброс/сборку в текущем Linux.

person ninjalj    schedule 27.01.2011
comment
Отличная работа. По сути, это то, что я нашел в своих следах, но вы указали настоящую причину. Интересно, почему дейтаграммы имеют этот предел, а не потоки? - person Jaime; 28.01.2011
comment
Сокеты SOCK_STREAM не сохраняют границы сообщений. - person ninjalj; 28.01.2011
comment
См. также расширенный ответ по адресу stackoverflow.com/questions/21856517/ - person Jonathan Ben-Avraham; 22.08.2014
comment
Сокеты SOCK_STREAM наверняка сохраняют границы сообщений. Просто поместите каждое сообщение в отдельный поток: создайте новый сокет, подключите его, напишите сообщение, закройте его в направлении отправки, получите ответ и отключитесь. Затем повторите для следующего сообщения. Другими словами, соединения поддерживают кадрирование, потому что они четко определяют начало потока и сигнализацию конца потока; они просто не поддерживают кадрирование в потоке. Точно так же, как сокеты SOCK_DGRAM не поддерживают кадрирование в дейтаграмме. - person Kaz; 07.03.2016
comment
@Kaz, значит, они этого не делают, и ты должен притворяться. - person lvella; 10.09.2019