Атомарная запись в сокете 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
из-за недостаточного размера буфера трубы размер.