Пример передачи учетных данных приводится в файлах scm_cred_send.c и scm_cred_recv.c внутри подкаталога sockets, которые предоставлены с исходным кодом к данной книге.
57.13.5. Последовательный обмен пакетами
Сокеты с поддержкой последовательного обмена пакетами объединяют в себе возможности потоковых и датаграммных сокетов.
• Как и потоковые сокеты, они ориентированы на работу с соединениями, которые устанавливаются тем же способом — с помощью вызовов bind(), listen(), accept() и connect().
• Как и датаграммные сокеты, они способны различать границы между сообщениями. Операция чтения из такого сокета возвращает ровно одно сообщение (записанное удаленной стороной). Если длина сообщения превышает размер буфера, предоставленного вызывающим процессом, лишние байты теряются.
• По аналогии с потоковыми сокетами (но в отличие от датаграммных) взаимодействие является надежным. Сообщения передаются адресату без ошибок, в том же порядке, в котором были отправлены, без дубликатов и с гарантией доставки (при условии отсутствия перегрузки сети или системных/программных сбоев).
Сокеты с поддержкой последовательного обмена пакетами создаются путем передачи аргументу type вызова socket() значения SOCK_SEQPACKET.
Изначально в Linux, как и в большинстве других UNIX-систем, не поддерживались сокеты такого типа, вне зависимости от домена. Однако в ядре 2.6.4 появилась поддержка сокетов SOCK_SEQPACKET в домене UNIX.
В интернет-домене эти сокеты поддерживаются исключительно протоколом SCTP (который описан в следующем разделе). То есть в UDP и TCP их поддержка отсутствует.
Последовательный обмен пакетами очень похож на работу потоковых сокетов (за исключением соблюдения границ сообщений), так что мы не станем приводить пример его использования.
57.13.6. Протоколы транспортного уровня SCTP и DCCP
SCTP и DCCP — относительно новые протоколы транспортного уровня, которые в будущем имеют шанс стать довольно распространенными.
SCTP (от англ. Stream Control Transmission Protocol — «протокол передачи с управлением потоком»; www.sctp.org) является протоколом общего назначения, хотя разрабатывался с упором на обмен телефонными сигналами. В отличие от TCP, он соблюдает границы отдельных сообщений. Одна из его отличительных черт — поддержка многопоточной передачи, что позволяет использовать несколько логических потоков данных в рамках одного соединения.
Протокол SCTP описан в книгах [Stewart & Xie, 2001], [Stevens et al., 2004], а также в документах RFC 4960, 3257 и 3286. Он доступен в Linux, начиная с версии ядра 2.6. Подробные сведения о его реализации можно найти на lksctp.sourceforge.net.
В предыдущих главах, посвященных программному интерфейсу сокетов, мы исходили из того, что потоковые сокеты в интернет-домене работают по протоколу TCP. Но на самом деле для потоковых сокетов существует альтернатива — протокол SCTP, который можно указать следующим образом:
socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
Начиная с версии 2.6.14 ядро Linux поддерживает новый датаграммный протокол DCCP (Datagram Congestion Control Protocol). Как и TCP, он предоставляет средства контроля перегрузок (устраняя необходимость в реализации подобных механизмов на уровне приложения), защищающие сеть от перегрузки слишком активной передающей стороной (принцип их работы был рассмотрен в подразделе 54.6.3 при описании протокола TCP). Но, в отличие от TCP (и по аналогии с UDP), протокол DCCP не обеспечивает надежную доставку и упорядоченность пакетов; благодаря этому приложения, которым не нужны такие возможности, могут избежать связанных с ними задержек. Информацию о протоколе DCCP можно найти на www.read.cs.ucla.edu/dccp/ и в документах RFC 4336 и 4340.
В различных ситуациях при выполнении операций ввода/вывода с потоковыми сокетами можно столкнуться с частичным чтением или записью. Мы продемонстрировали реализацию двух функций, readn() и writen(), которые гарантируют чтение или запись всех данных в буфере.
Системный вызов shutdown() предоставляет более тонкий контроль над процедурой разрыва соединения. С его помощью можно принудительно закрыть один или оба канала двунаправленного потока взаимодействия; при этом не важно, существуют ли другие файловые дескрипторы, ссылающиеся на наш сокет.
Вызовы recv() и send() — аналоги операций read() и write() и могут быть использованы для выполнения ввода/вывода через сокет. Их особенностью является дополнительный аргумент flags, влияющий на различные аспекты ввода/вывода, относящиеся к сокетам.
Системный вызов sendfile() обеспечивает эффективное копирование содержимого файла в сокет. Эта эффективность достигается за счет предотвращения копирования данных в пользовательскую память и обратно, выполняемого вызовами read() и write().