Атомарная запись в сокете unix?

Я пытаюсь выбрать между труб и сокеты unix для механизма IPC.
Оба поддерживают select() и epoll() функции, которые велики.

Теперь трубы имеют 4KB (на сегодняшний день) "атомарную" запись, которая гарантируется ядром Linux.
Существует ли такая функция в случае сокетов unix? Я не нашел ни одного документа, в котором это было бы ясно сказано.

скажем, я использую сокет UNIX, и я пишу X байтов данных из моего клиент. Уверен ли я, что эти X байты будут записаны на серверной стороне сокета, когда мой сервер select() трещины?

по той же теме, будет ли использование SOCK_DGRAM гарантировать, что записи являются атомарными (если такая гарантия возможна), поскольку предполагается, что датаграммы быть отдельные четко определенные сообщения?
В чем тогда будет разница с использованием SOCK_STREAM в качестве режима передачи?

спасибо заранее.

2 ответов


труб

да, неблокирующая емкость обычно составляет 4 КБ, но для максимальной переносимости вам, вероятно, лучше использовать PIPE_BUF константы. Альтернативой является использование неблокирующего ввода-вывода.

больше информации, чем вы хотите узнать в man 7 pipe.

сокеты дейтаграмм Unix

пишет с помощью send семейство функций на сокетах дейтаграмм действительно гарантировано атомные. В случае Linux они надежный также, и сохраняйте заказ. (что делает недавнее введение SOCK_SEQPACKET немного смущает меня) много информации об этом в man 7 unix.

на максимальный размер дейтаграммы - это гнездо-зависимые. Это доступ через getsockopt/setsockopt on SO_SNDBUF. В системах Linux он колеблется между 2048 и wmem_max по умолчанию wmem_default. Например, в моей системе,wmem_default = wmem_max = 112640. (вы можете прочитать их из /proc/sys/net/core) наиболее соответствующая документация об этом находится в man 7 socket вокруг . Я рекомендую вам прочитать его самостоятельно, так как поведение удвоения емкости, которое он описывает, может быть немного запутанным.

практические различия между потоком и датаграммой

потоковые сокеты работают только подключенные. Это в основном означает, что они могут общаться только с одним сверстником за раз. Как потоки, они не гарантируют сохранение "границ сообщений".

сокеты дейтаграмм отключены. Они могут (теоретически) общаться с несколькими коллегами одновременно. Они сохраняют границы сообщений.

[я полагаю, что новый SOCK_SEQPACKET находится между: connected и сохранением границ.]

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

сырой бенчмарк сравнения потока, дейтаграммы и трубы:

# unix stream 0:05.67
socat UNIX-LISTEN:u OPEN:/dev/null &
until [[ -S u ]]; do :;done
time socat OPEN:large-file UNIX-CONNECT:u

# unix datagram 0:05.12
socat UNIX-RECV:u OPEN:/dev/null &
until [[ -S u ]]; do :;done
time socat OPEN:large-file UNIX-SENDTO:u

# pipe 0:05.44
socat PIPE:p,rdonly=1 OPEN:/dev/null &
until [[ -p p ]]; do :;done
time socat OPEN:large-file PIPE:p

здесь нет ничего статистически значимого. Мое узкое место, вероятно, читает большой файл.


скажем, я использую сокет UNIX, и я пишу x байты данных от моего клиента. Я уверен, что эти байты будут написано на серверном конце сокет, когда мой сервер select() трещины?

если вы используете AF_UNIX SOCK_STREAM сокет, такой гарантии нет, то есть данные написаны в одном write/send() может потребоваться более одного read/recv() звонок на принимающей стороне.

на ту же тему, будет использовать Sock_dgram обеспечить что пишет atomic (если такая гарантия возможно), так как датаграммы предполагается, что один четко определенный сообщения?

С другой стороны,AF_UNIX SOCK_DGRAM сокеты необходимы, чтобы сохранить границы дейтаграммы и быть надежными. Вы должны получить ошибку EMSGSIZE, если send() не может передать дейтаграмму атомарно. Не уверен, что происходит для write() поскольку man-страница не говорит, что она может сообщить EMSGSIZE (хотя man-страницы иногда не перечисляют все возвращенные ошибки). Я бы попытался переполнить буфер приемника датаграммами большого размера, чтобы увидеть, какие именно ошибки send/write() отчет.

одним из преимуществ использования сокетов UNIX над трубами является больший размер буфера. Я не помню точно, каков предел буфера ядра pipe, но я помню, что у меня его недостаточно и я не могу его увеличить (это жестко закодированная константа ядра). fast_producer_process | slow_consumer_process было на порядки медленнее, чем fast_producer_process > file && file > slow_consumer_process из-за недостаточного размера буфера трубы размер.