aboutsummaryrefslogtreecommitdiff
path: root/documentation/content/ru/books/developers-handbook/sockets
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/content/ru/books/developers-handbook/sockets')
-rw-r--r--documentation/content/ru/books/developers-handbook/sockets/_index.adoc909
-rw-r--r--documentation/content/ru/books/developers-handbook/sockets/_index.po3021
2 files changed, 3930 insertions, 0 deletions
diff --git a/documentation/content/ru/books/developers-handbook/sockets/_index.adoc b/documentation/content/ru/books/developers-handbook/sockets/_index.adoc
new file mode 100644
index 0000000000..669a53fb60
--- /dev/null
+++ b/documentation/content/ru/books/developers-handbook/sockets/_index.adoc
@@ -0,0 +1,909 @@
+---
+authors:
+ -
+ author: 'G. Adam Stanislav'
+description: 'Сокеты FreeBSD'
+next: books/developers-handbook/ipv6
+params:
+ path: /books/developers-handbook/sockets/
+prev: books/developers-handbook/partii
+showBookMenu: true
+tags: ["Sockets", "Protocols"]
+title: 'Глава 7. Сокеты'
+weight: 9
+---
+
+[[sockets]]
+= Сокеты
+:doctype: book
+:toc: macro
+:toclevels: 1
+:icons: font
+:sectnums:
+:sectnumlevels: 6
+:sectnumoffset: 7
+:partnums:
+:source-highlighter: rouge
+:experimental:
+:images-path: books/developers-handbook/
+
+ifdef::env-beastie[]
+ifdef::backend-html5[]
+:imagesdir: ../../../../images/{images-path}
+endif::[]
+ifndef::book[]
+include::shared/authors.adoc[]
+include::shared/mirrors.adoc[]
+include::shared/releases.adoc[]
+include::shared/attributes/attributes-{{% lang %}}.adoc[]
+include::shared/{{% lang %}}/teams.adoc[]
+include::shared/{{% lang %}}/mailing-lists.adoc[]
+include::shared/{{% lang %}}/urls.adoc[]
+toc::[]
+endif::[]
+ifdef::backend-pdf,backend-epub3[]
+include::../../../../../shared/asciidoctor.adoc[]
+endif::[]
+endif::[]
+
+ifndef::env-beastie[]
+toc::[]
+include::../../../../../shared/asciidoctor.adoc[]
+endif::[]
+
+[[sockets-synopsis]]
+== Обзор
+
+Сокеты BSD выводят межпроцессное взаимодействие на новый уровень. Теперь взаимодействующие процессы не обязательно должны выполняться на одной машине. Они всё ещё _могут_, но не обязаны.
+
+Не только эти процессы не обязаны выполняться на одной машине, они также могут работать под разными операционными системами. Благодаря BSD-сокетам, ваше ПО на FreeBSD может легко взаимодействовать с программой, работающей на Macintosh(R), другой — на рабочей станции Sun(TM), и ещё одной — под Windows(R) 2000, при этом все они подключены к локальной сети на основе Ethernet.
+
+Но ваше программное обеспечение может так же эффективно взаимодействовать с процессами, работающими в другом здании, на другом континенте, внутри подводной лодки или космического челнока.
+
+Он также может взаимодействовать с процессами, которые не являются частью компьютера (по крайней мере, не в строгом смысле этого слова), а таких устройств, как принтеры, цифровые камеры, медицинское оборудование. Практически со всем, что способно к цифровой коммуникации.
+
+[[sockets-diversity]]
+== Сетевое взаимодействие и разнообразие
+
+Мы уже упоминали о _разнообразии_ сетевых технологий. Множество различных систем должны взаимодействовать друг с другом. И они должны говорить на одном языке. Также они должны _понимать_ этот язык одинаковым образом.
+
+Часто думают, что _язык тела_ универсален. Но это не так. В ранней юности отец взял меня с собой в Болгарию. Мы сидели за столиком в парке Софии, когда к нам подошел продавец, предлагая купить жареный миндаль.
+
+Я тогда еще не знал болгарского, поэтому вместо словесного отказа я покачал головой из стороны в сторону — это «универсальный» язык тела для обозначения _нет_. Продавец тут же начал угощать нас миндалем.
+
+Затем я вспомнил, что мне говорили, будто в Болгарии покачивание головой из стороны в сторону означает _да_. Быстро я начал кивать головой вверх-вниз. Продавец заметил, взял свои миндалины и ушёл. Для непосвящённого наблюдателя я не изменил язык тела: я продолжал использовать движения головой — покачивание и кивание. Изменился _смысл_ языка тела. Сначала продавец и я интерпретировали одни и те же жесты как имеющие совершенно разный смысл. Мне пришлось скорректировать свою собственную интерпретацию этих жестов, чтобы продавец меня понял.
+
+То же самое и с компьютерами: одни и те же символы могут иметь разное, даже полностью противоположное значение. Поэтому, чтобы два компьютера понимали друг друга, они должны договориться не только об одном _языке_, но и об одном _толковании_ языка.
+
+[[sockets-protocols]]
+== Протоколы
+
+В то время как различные языки программирования обычно имеют сложный синтаксис и используют множество многосимвольных зарезервированных слов (что облегчает их понимание для человека-программиста), языки передачи данных, как правило, очень лаконичны. Вместо многосимвольных слов они часто используют отдельные _биты_. Для этого есть очень убедительная причина: хотя данные внутри вашего компьютера передаются со скоростью, близкой к скорости света, между двумя компьютерами они часто передаются значительно медленнее.
+
+Поскольку языки, используемые в передаче данных, настолько лаконичны, мы обычно называем их _протоколами_, а не языками.
+
+При передаче данных от одного компьютера к другому всегда используется более одного протокола. Эти протоколы _располагаются слоями_. Данные можно сравнить с внутренней частью лука: необходимо снять несколько слоёв «кожи», чтобы добраться до данных. Это лучше всего проиллюстрировано на рисунке:
+
+.Уровни протоколов
+image::layers.png[]
+
+В этом примере мы пытаемся получить изображение с веб-страницы, к которой подключены через Ethernet.
+
+Изображение состоит из необработанных данных, которые представляют собой просто последовательность значений RGB, которые наше программное обеспечение может обработать, т.е. преобразовать в изображение и отобразить на нашем мониторе.
+
+Увы, наше программное обеспечение не может определить, как организованы сырые данные: это последовательность значений RGB, последовательность интенсивностей в градациях серого или, возможно, цвета в кодировке CMYK? Представлены ли данные 8-битными квантами, или они имеют размер 16 бит, а может быть, 4 бита? Из скольких строк и столбцов состоит изображение? Должны ли определённые пиксели быть прозрачными?
+
+Я думаю, вы поняли...
+
+Чтобы наше программное обеспечение понимало, как обрабатывать сырые данные, они кодируются в формате PNG. Это мог бы быть GIF или JPEG, но выбран PNG.
+
+И PNG — это протокол.
+
+В этот момент я слышу, как некоторые из вас кричат: _"Нет, это не так! Это формат файла!"_
+
+Ну что ж, конечно, это формат файла. Но с точки зрения передачи данных, формат файла — это протокол: структура файла — это _язык_, причем лаконичный, сообщающий нашему _процессу_, как организованы данные. Следовательно, это _протокол_.
+
+Увы, если бы мы получили только PNG-файл, наше программное обеспечение столкнулось бы с серьёзной проблемой: как ему узнать, что данные представляют изображение, а не текст, звук или что-то ещё? Во-вторых, как ему определить, что изображение сохранено в формате PNG, а не GIF, JPEG или каком-либо другом формате изображений?
+
+Для получения этой информации мы используем другой протокол: HTTP. Этот протокол может точно сообщить нам, что данные представляют изображение и используют протокол PNG. Он также может сообщить некоторые другие сведения, но давайте сосредоточимся на уровнях протоколов здесь.
+
+Итак, теперь у нас есть некоторые данные, упакованные в протокол PNG, который в свою очередь упакован в протокол HTTP. Как мы получили их с сервера?
+
+Используя TCP/IP поверх Ethernet, вот как. Действительно, это ещё три протокола. Вместо того чтобы продолжать изнутри наружу, я теперь расскажу про Ethernet, просто потому что так проще объяснить остальное.
+
+Ethernet — это интересная система соединения компьютеров в _локальной сети_ (LAN). У каждого компьютера есть _карта сетевого интерфейса_ (NIC — Network Interface Card) с уникальным 48-битным идентификатором, называемым _адресом_. Не существует двух сетевых интерфейсов Ethernet в мире с одинаковым адресом.
+
+Эти сетевые карты соединены между собой. Когда один компьютер хочет связаться с другим в той же локальной сети Ethernet, он отправляет сообщение по сети. Каждая сетевая карта видит это сообщение. Однако, согласно _протоколу_ Ethernet, данные содержат адрес сетевой карты назначения (среди прочего). Таким образом, только одна из всех сетевых карт обратит на него внимание, остальные проигнорируют его.
+
+Но не все компьютеры подключены к одной сети. Тот факт, что мы получили данные через наш Ethernet, не означает, что они возникли в нашей локальной сети. Они могли попасть к нам из другой сети (которая может быть даже не на основе Ethernet), соединённой с нашей сетью через Интернет.
+
+Все данные передаются через Интернет с использованием IP, что означает _Internet Protocol_. Его основная роль — сообщать нам, откуда в мире пришли данные и куда они должны быть направлены. Он не _гарантирует_, что мы получим данные, только что мы узнаем, откуда они пришли, _если_ мы их получим.
+
+Даже если мы получим данные, IP не гарантирует, что различные фрагменты данных придут в том же порядке, в котором их отправил другой компьютер. Например, мы можем получить центр нашего изображения до того, как получим его верхний левый угол, а после — нижний правый.
+
+Это TCP (_Transmission Control Protocol_), который запрашивает у отправителя повторную отправку потерянных данных и располагает их в правильном порядке.
+
+В итоге потребовалось _пять_ различных протоколов, чтобы один компьютер мог сообщить другому, как выглядит изображение. Мы получили данные, упакованные в протокол PNG, который был упакован в протокол HTTP, который был упакован в протокол TCP, который был упакован в протокол IP, который был упакован в протокол Ethernet.
+
+О, и кстати, вероятно, на пути были задействованы и несколько других протоколов. Например, если наша локальная сеть была подключена к Интернету через дозвон, то использовался протокол PPP над модемом, который, в свою очередь, использовал один (или несколько) из различных модемных протоколов, и так далее, и так далее, и так далее...
+
+Как разработчик, вы уже должны задаваться вопросом: _"Как я должен со всем этим справляться?"_
+
+К счастью для вас, вам _не_ нужно разбираться во всём этом. Вам _придётся_ разобраться в некоторой части, но не во всей. В частности, вам не нужно беспокоиться о физическом подключении (в нашем случае Ethernet и, возможно, PPP и т.д.). Также вам не нужно разбираться с протоколом IP или протоколом TCP.
+
+Другими словами, вам не нужно ничего делать, чтобы получить данные с другого компьютера. Ну, разве что _попросить_ их, но это почти так же просто, как открыть файл.
+
+Получив данные, вам предстоит решить, что с ними делать. В нашем случае потребуется понимание протокола HTTP и структуры файла PNG.
+
+Используя аналогию, все межсетевые протоколы становятся серой зоной: не столько потому, что мы не понимаем, как они работают, а потому, что нас это больше не беспокоит. Интерфейс сокетов берёт на себя заботу об этой серой зоне:
+
+.Уровни протоколов, покрываемые сокетами
+image::slayers.png[]
+
+Нам нужно понимать только те протоколы, которые говорят нам, как _интерпретировать данные_, а не как _получать_ их от другого процесса или как _передавать_ их другому процессу.
+
+[[sockets-model]]
+== Модель сокетов
+
+Сокеты BSD построены по базовой модели UNIX(R): _Все является файлом._ Таким образом, в нашем примере сокеты позволят нам получить, образно говоря, _HTTP-файл_. Затем нам предстоит извлечь из него _PNG-файл_.
+
+Из-за сложности межсетевого взаимодействия мы не можем просто использовать системный вызов `open` или функцию `open()` в языке C. Вместо этого необходимо выполнить несколько шагов для "открытия" сокета.
+
+Однако, как только мы это сделаем, мы можем начать обращаться с _сокетом_ так же, как и с любым _файловым дескриптором_: мы можем `читать` из него, `писать` в него, передавать его через `канал` и, в конечном итоге, `закрывать` его.
+
+[[sockets-essential-functions]]
+== Основные функции сокетов
+
+В то время как FreeBSD предлагает различные функции для работы с сокетами, нам _требуется_ только четыре, чтобы "открыть" сокет. А в некоторых случаях достаточно двух.
+
+[[sockets-client-server]]
+=== Разница между клиентом и сервером
+
+Обычно одним из концов связи на основе сокетов является _сервер_, а другой — _клиент_.
+
+[[sockets-common-elements]]
+==== Общие элементы
+
+[[sockets-socket]]
+===== `socket`
+
+Функция, используемая как клиентами, так и серверами, это man:socket[2]. Она объявляется следующим образом:
+
+[.programlisting]
+....
+int socket(int domain, int type, int protocol);
+....
+
+Возвращаемое значение имеет тот же тип, что и у `open`, целое число. FreeBSD выделяет его значение из того же пула, что и дескрипторы файлов. Это позволяет обрабатывать сокеты так же, как файлы.
+
+Аргумент `domain` указывает системе, какое _семейство протоколов_ следует использовать. Существует множество семейств, некоторые из них специфичны для определённых поставщиков, другие широко распространены. Они объявлены в [.filename]#sys/socket.h#.
+
+Используйте `PF_INET` для UDP, TCP и других интернет-протоколов (IPv4).
+
+Для аргумента `type` определено пять значений, также указанных в [.filename]#sys/socket.h#. Все они начинаются с "`SOCK_`". Наиболее распространённое — `SOCK_STREAM`, которое указывает системе, что запрашивается _надёжный сервис потоковой доставки_ (это TCP при использовании с `PF_INET`).
+
+Если бы вы запросили `SOCK_DGRAM`, вы бы запросили _сервис доставки датаграмм без установления соединения_ (в нашем случае, UDP).
+
+Если вы хотите управлять низкоуровневыми протоколами (такими как IP) или даже сетевыми интерфейсами (например, Ethernet), вам потребуется указать `SOCK_RAW`.
+
+Наконец, аргумент `protocol` зависит от двух предыдущих аргументов и не всегда имеет смысл. В таком случае используйте значение `0`.
+
+[NOTE]
+.Неподключенный сокет
+====
+Нигде в функции `socket` мы не указали, к какой другой системе должны быть подключены. Наш только что созданный сокет остаётся _неподключённым_.
+
+Это сделано намеренно: если проводить аналогию с телефоном, мы только что подключили модем к телефонной линии. Мы не сказали модему совершить звонок или ответить, если телефон зазвонит.
+====
+
+[[sockets-sockaddr]]
+===== `sockaddr`
+
+Различные функции семейства сокетов ожидают адрес (или указатель, если использовать терминологию языка C) небольшой области памяти. Различные объявления на языке C в файле [.filename]#sys/socket.h# ссылаются на неё как на `struct sockaddr`. Эта структура объявлена в том же файле:
+
+[.programlisting]
+....
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ unsigned char sa_len; /* total length */
+ sa_family_t sa_family; /* address family */
+ char sa_data[14]; /* actually longer; address value */
+};
+#define SOCK_MAXADDRLEN 255 /* longest possible addresses */
+....
+
+Обратите внимание на _неопределённость_, с которой объявлено поле `sa_data` — просто как массив из `14` байт, с комментарием, намекающим, что их может быть больше `14`.
+
+Эта неопределенность вполне преднамеренна. Сокеты — это очень мощный интерфейс. Хотя большинство людей, возможно, считают их не более чем интерфейсом для Интернета — и большинство приложений, вероятно, используют их именно для этого в наши дни — сокеты могут быть использованы практически для _любого_ вида межпроцессного взаимодействия, из которых Интернет (или, точнее, IP) — лишь один из них.
+
+[.filename]#sys/socket.h# ссылается на различные типы протоколов, с которыми работают сокеты, как на _семейства адресов_, и перечисляет их непосредственно перед определением `sockaddr`:
+
+[.programlisting]
+....
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_LOCAL 1 /* local to host (pipes, portals) */
+#define AF_UNIX AF_LOCAL /* backward compatibility */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_ISO 7 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_ECMA 8 /* European computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* DEC Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_ROUTE 17 /* Internal Routing Protocol */
+#define AF_LINK 18 /* Link layer interface */
+#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+#define AF_COIP 20 /* connection-oriented IP, aka ST II */
+#define AF_CNT 21 /* Computer Network Technology */
+#define pseudo_AF_RTIP 22 /* Help Identify RTIP packets */
+#define AF_IPX 23 /* Novell Internet Protocol */
+#define AF_SIP 24 /* Simple Internet Protocol */
+#define pseudo_AF_PIP 25 /* Help Identify PIP packets */
+#define AF_ISDN 26 /* Integrated Services Digital Network*/
+#define AF_E164 AF_ISDN /* CCITT E.164 recommendation */
+#define pseudo_AF_KEY 27 /* Internal key-management function */
+#define AF_INET6 28 /* IPv6 */
+#define AF_NATM 29 /* native ATM access */
+#define AF_ATM 30 /* ATM */
+#define pseudo_AF_HDRCMPLT 31 /* Used by BPF to not rewrite headers
+ * in interface output routine
+ */
+#define AF_NETGRAPH 32 /* Netgraph sockets */
+#define AF_SLOW 33 /* 802.3ad slow protocol */
+#define AF_SCLUSTER 34 /* Sitara cluster protocol */
+#define AF_ARP 35
+#define AF_BLUETOOTH 36 /* Bluetooth sockets */
+#define AF_MAX 37
+....
+
+Используемый для IP — это AF_INET. Это символ для константы `2`.
+
+Это _семейство адресов_, указанное в поле `sa_family` структуры `sockaddr`, определяет, как именно будут использоваться нечетко названные байты `sa_data`.
+
+В частности, когда _семейство адресов_ — AF_INET, можно использовать `struct sockaddr_in` из [.filename]#netinet/in.h# везде, где ожидается `sockaddr`:
+
+[.programlisting]
+....
+/*
+ * Socket address, internet style.
+ */
+struct sockaddr_in {
+ uint8_t sin_len;
+ sa_family_t sin_family;
+ in_port_t sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+};
+....
+
+Мы можем визуализировать его организацию следующим образом:
+
+.Структура `sockaddr_in`
+image::sain.png[]
+
+Три важных поля — это `sin_family`, которое находится в байте 1 структуры, `sin_port`, 16-битное значение, расположенное в байтах 2 и 3, и `sin_addr`, 32-битное целочисленное представление IP-адреса, хранящееся в байтах 4–7.
+
+Теперь попробуем заполнить его. Предположим, мы пытаемся написать клиент для протокола _daytime_, который просто указывает, что его сервер записывает текстовую строку с текущей датой и временем в порт 13. Мы хотим использовать TCP/IP, поэтому нам нужно указать `AF_INET` в поле семейства адресов. `AF_INET` определен как `2`. Давайте используем IP-адрес `192.43.244.18`, который является сервером времени федерального правительства США (`time.nist.gov`).
+
+.Конкретный пример sockaddr_in
+image::sainfill.png[]
+
+Кстати, поле `sin_addr` объявлено как имеющее тип `struct in_addr`, который определён в [.filename]#netinet/in.h#:
+
+[.programlisting]
+....
+/*
+ * Internet address (a structure for historical reasons)
+ */
+struct in_addr {
+ in_addr_t s_addr;
+};
+....
+
+В дополнение, `in_addr_t` является 32-битным целым числом.
+
+`192.43.244.18` — это просто удобная форма записи 32-битного целого числа, в которой перечисляются все его 8-битные байты, начиная с _старшего_.
+
+До сих пор мы рассматривали `sockaddr` как абстракцию. Наш компьютер не хранит `short` целые числа как единую 16-битную сущность, а как последовательность 2 байт. Аналогично, он хранит 32-битные целые числа как последовательность 4 байт.
+
+Предположим, мы написали что-то вроде этого:
+
+[.programlisting]
+....
+sa.sin_family = AF_INET;
+sa.sin_port = 13;
+sa.sin_addr.s_addr = (((((192 << 8) | 43) << 8) | 244) << 8) | 18;
+....
+
+Как будет выглядеть результат?
+
+Ну, это, конечно, зависит от многого. На компьютере с процессором Pentium(R) или другим на базе x86 это будет выглядеть так:
+
+.`sockaddr_in` в системе с архитектурой Intel
+image::sainlsb.png[]
+
+На другой системе это может выглядеть так:
+
+.`sockaddr_in` в системе с порядком байтов от старшего к младшему
+image::sainmsb.png[]
+
+И на PDP это может выглядеть иначе. Однако два приведённых выше варианта являются наиболее распространёнными на сегодняшний день.
+
+Обычно, стремясь писать переносимый код, программисты делают вид, что этих различий не существует. И им это сходит с рук (за исключением случаев, когда они пишут на ассемблере). Увы, при программировании сокетов так легко отделаться не получится.
+
+Почему?
+
+Потому что при обмене данными с другим компьютером вы обычно не знаете, хранит ли он данные, начиная со _старшего байта_ (MSB) или с _младшего байта_ (LSB).
+
+Вы можете задаться вопросом: _"Значит, сокеты не будут это делать за меня?"_
+
+Не будут.
+
+Хотя этот ответ может сначала вас удивить, помните, что общий интерфейс сокетов понимает только поля `sa_len` и `sa_family` структуры `sockaddr`. Вам не нужно беспокоиться о порядке байтов (конечно, в FreeBSD `sa_family` занимает всего 1 байт, но многие другие UNIX(R)-системы не имеют `sa_len` и используют 2 байта для `sa_family`, ожидая данные в том порядке, который является родным для компьютера).
+
+Но остальные данные — это просто `sa_data[14]` с точки зрения сокетов. В зависимости от _семейства адресов_ сокеты просто передают эти данные по назначению.
+
+Действительно, когда мы указываем номер порта, это делается для того, чтобы другая компьютерная система знала, какую службу мы запрашиваем. И, когда мы выступаем в роли сервера, мы считываем номер порта, чтобы понять, какую службу ожидает от нас другая система. В любом случае, сокетам нужно лишь передать номер порта в качестве данных. Они никак его не интерпретируют.
+
+Аналогично, мы указываем IP-адрес, чтобы сообщить всем на пути, куда отправлять наши данные. Сокеты, опять же, просто пересылают их как данные.
+
+Вот почему мы (программисты, а не сокеты) должны различать порядок байтов, используемый нашим компьютером, и условный порядок байтов для отправки данных на другой компьютер.
+
+Мы будем называть порядок байтов, который использует наш компьютер, _порядком байтов хоста_ или просто _хост-порядком_.
+
+Существует соглашение о передаче многобайтовых данных по IP _старшим байтом вперёд_. Это мы будем называть _порядком байтов сети_ или просто _сетевым порядком_.
+
+Вот, если бы мы скомпилировали приведённый выше код для компьютера на базе Intel, наш _порядок байтов хоста_ выдал бы:
+
+.Порядок байтов на хосте в системе Intel
+image::sainlsb.png[]
+
+Но порядок байтов в _сетевом формате_ требует, чтобы данные хранились начиная со старшего байта (MSB):
+
+.Порядок байтов в сети
+image::sainmsb.png[]
+
+К сожалению, наш _порядок хоста_ полностью противоположен _порядку сети_.
+
+У нас есть несколько способов решения этой проблемы. Один из них — _инвертировать_ значения в нашем коде:
+
+[.programlisting]
+....
+sa.sin_family = AF_INET;
+sa.sin_port = 13 << 8;
+sa.sin_addr.s_addr = (((((18 << 8) | 244) << 8) | 43) << 8) | 192;
+....
+
+Это _обманет_ наш компилятор, заставив его сохранить данные в _порядке байтов сети_. В некоторых случаях это именно тот способ, который нужен (например, при программировании на ассемблере). Однако в большинстве случаев это может вызвать проблему.
+
+Предположим, вы написали программу на C, использующую сокеты. Вы знаете, что она будет работать на Pentium(R), поэтому вводите все константы в обратном порядке и приводите их к _порядку байтов сети_. Она работает хорошо.
+
+Затем, однажды, ваш надежный старый Pentium(R) превращается в ржавый старый Pentium(R). Вы заменяете его системой, у которой _порядок байтов хоста_ совпадает с _сетевым порядком байтов_. Вам нужно перекомпилировать все ваше программное обеспечение. Все ваши программы продолжают работать хорошо, кроме той одной программы, которую вы написали.
+
+Вы уже забыли, что принудительно задали все свои константы противоположными _порядку хоста_. Вы проводите некоторое время, яростно рвя на себе волосы, взывая ко всем известным вам богам (и к некоторым, которых вы придумали), стуча нерф-битой по монитору и выполняя прочие традиционные ритуалы в попытке понять, почему то, что работало так хорошо, внезапно перестало работать вообще.
+
+В конце концов, вы разбираетесь в проблеме, произносите пару крепких словечек и начинаете переписывать свой код.
+
+К счастью, вы не первый, кто столкнулся с этой проблемой. Кто-то уже создал функции man:htons[3] и man:htonl[3] на языке C для преобразования `short` и `long` соответственно из _порядка байтов хоста_ в _порядок байтов сети_, а также функции man:ntohs[3] и man:ntohl[3] на языке C для обратного преобразования.
+
+На системах с порядком _старший байт первый_ эти функции не выполняют никаких действий. На системах с порядком _младший байт первый_ они преобразуют значения в правильный порядок.
+
+Итак, независимо от того, на какой системе компилируется ваше программное обеспечение, ваши данные будут в правильном порядке, если вы используете эти функции.
+
+[[sockets-client-functions]]
+==== Функции клиента
+
+Обычно клиент инициирует подключение к серверу. Клиент знает, к какому серверу он собирается обратиться: он знает его IP-адрес и _порт_, на котором работает сервер. Это похоже на то, как вы поднимаете трубку и набираете номер (_адрес_), а затем, когда кто-то отвечает, просите соединить со специалистом по непонятным символам (_порт_).
+
+[[sockets-connect]]
+===== `connect`
+
+Как только клиент создал сокет, ему нужно подключить его к определённому порту на удалённой системе. Для этого используется man:connect[2]:
+
+[.programlisting]
+....
+int connect(int s, const struct sockaddr *name, socklen_t namelen);
+....
+
+Аргумент `s` — это сокет, то есть значение, возвращаемое функцией `socket`. Аргумент `name` — это указатель на структуру `sockaddr`, которую мы подробно обсуждали. Наконец, `namelen` сообщает системе, сколько байт находится в нашей структуре `sockaddr`.
+
+Если `connect` завершается успешно, он возвращает `0`. В противном случае возвращается `-1`, а код ошибки сохраняется в `errno`.
+
+Существует множество причин, по которым `connect` может завершиться неудачей. Например, при попытке подключения к интернету, IP-адрес может не существовать, быть недоступен, перегружен или на указанном порту может не быть сервера. Или же подключение может быть явно _отклонено_ по определённым причинам.
+
+[[sockets-first-client]]
+===== Наш первый клиент
+
+Теперь мы знаем достаточно, чтобы написать очень простого клиента, который получит текущее время от `192.43.244.18` и выведет его в [.filename]#stdout#.
+
+[.programlisting]
+....
+/*
+ * daytime.c
+ *
+ * Programmed by G. Adam Stanislav
+ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+int main() {
+ int s, bytes;
+ struct sockaddr_in sa;
+ char buffer[BUFSIZ+1];
+
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ return 1;
+ }
+
+ memset(&sa, '\0', sizeof(sa));
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(13);
+ sa.sin_addr.s_addr = htonl((((((192 << 8) | 43) << 8) | 244) << 8) | 18);
+ if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
+ perror("connect");
+ close(s);
+ return 2;
+ }
+
+ while ((bytes = read(s, buffer, BUFSIZ)) > 0)
+ write(1, buffer, bytes);
+
+ close(s);
+ return 0;
+}
+....
+
+Вперед! Введите это в вашем редакторе, сохраните как [.filename]#daytime.c#, затем скомпилируйте и запустите:
+
+[source, bash]
+....
+% cc -O3 -o daytime daytime.c
+% ./daytime
+
+52079 01-06-19 02:29:25 50 0 1 543.9 UTC(NIST) *
+%
+....
+
+В данном случае дата была 19 июня 2001 года, время — 02:29:25 UTC. Естественно, ваши результаты могут отличаться.
+
+[[sockets-server-functions]]
+==== Функции сервера
+
+Типичный сервер не инициирует соединение. Вместо этого он ожидает, когда клиент обратится к нему и запросит услуги. Он не знает, когда клиент обратится, ни сколько клиентов обратится. В один момент он может просто спокойно ожидать, а в следующий момент он может оказаться перегруженным запросами от множества клиентов, обращающихся одновременно.
+
+Интерфейс сокетов предоставляет три основные функции для обработки этого.
+
+[[sockets-bind]]
+===== `bind`
+
+Порты подобны внутренним номерам телефонной линии: после набора основного номера вы набираете внутренний номер, чтобы связаться с конкретным человеком или отделом.
+
+Существует 65535 IP-портов, но сервер обычно обрабатывает запросы, поступающие только на один из них. Это как сказать оператору телефонной комнаты, что мы сейчас на месте и готовы отвечать на звонки по определённому внутреннему номеру. Мы используем man:bind[2], чтобы указать сокетам, на каком порту мы хотим обслуживать запросы.
+
+[.programlisting]
+....
+int bind(int s, const struct sockaddr *addr, socklen_t addrlen);
+....
+
+Помимо указания порта в `addr`, сервер может включать свой IP-адрес. Однако он может просто использовать символическую константу INADDR_ANY, чтобы указать, что будет обслуживать все запросы на указанный порт, независимо от его IP-адреса. Этот символ, наряду с несколькими аналогичными, объявлен в [.filename]#netinet/in.h#
+
+[.programlisting]
+....
+#define INADDR_ANY (u_int32_t)0x00000000
+....
+
+Предположим, мы пишем сервер для протокола _daytime_ поверх TCP/IP. Напомним, что он использует порт 13. Наша структура `sockaddr_in` будет выглядеть так:
+
+.Пример sockaddr_in сервера
+image::sainserv.png[]
+
+[[sockets-listen]]
+===== `listen`
+
+Продолжая аналогию с офисным телефоном, после того как вы сообщили оператору АТС, на каком внутреннем номере вы будете находиться, вы заходите в свой офис и убеждаетесь, что ваш телефон подключен и звонок включен. Кроме того, вы активируете функцию ожидания вызова, чтобы слышать звонок даже во время разговора с кем-то.
+
+Сервер обеспечивает все это с помощью функции man:listen[2].
+
+[.programlisting]
+....
+int listen(int s, int backlog);
+....
+
+Здесь переменная `backlog` указывает сокетам, сколько входящих запросов принимать, пока вы заняты обработкой последнего запроса. Другими словами, она определяет максимальный размер очереди ожидающих соединений.
+
+[[sockets-accept]]
+===== `accept`
+
+После того как вы услышите телефонный звонок, вы принимаете вызов, отвечая на звонок. Теперь вы установили соединение с вашим клиентом. Это соединение остается активным, пока вы или ваш клиент не повесите трубку.
+
+Сервер принимает соединение, используя функцию man:accept[2].
+
+[.programlisting]
+....
+int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+....
+
+Обратите внимание, что в этот раз `addrlen` является указателем. Это необходимо, потому что в данном случае именно сокет заполняет структуру `addr` — `sockaddr_in`.
+
+Возвращаемое значение является целым числом. Действительно, `accept` возвращает _новый сокет_. Этот новый сокет будет использоваться для обмена данными с клиентом.
+
+Что происходит со старым сокетом? Он продолжает ожидать новые запросы (помните переменную `backlog`, которую мы передали в `listen`?), пока мы не закроем его (`close`).
+
+Теперь новый сокет предназначен только для обмена данными. Он полностью подключен. Мы не можем снова передать его в `listen`, чтобы принимать дополнительные соединения.
+
+[[sockets-first-server]]
+===== Наш первый сервер
+
+Наш первый сервер будет несколько сложнее, чем первый клиент: нам нужно не только использовать больше функций сокетов, но и написать его как демон.
+
+Это лучше всего достигается созданием _дочернего процесса_ после привязки порта. Затем основной процесс завершается и возвращает управление оболочке (или любой другой программе, которая его вызвала).
+
+Дочерний процесс вызывает `listen`, затем запускает бесконечный цикл, который принимает соединение, обслуживает его и в конечном итоге закрывает свой сокет.
+
+[.programlisting]
+....
+/*
+ * daytimed - a port 13 server
+ *
+ * Programmed by G. Adam Stanislav
+ * June 19, 2001
+ */
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#define BACKLOG 4
+
+int main() {
+ int s, c;
+ socklen_t b;
+ struct sockaddr_in sa;
+ time_t t;
+ struct tm *tm;
+ FILE *client;
+
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ return 1;
+ }
+
+ memset(&sa, '\0', sizeof(sa));
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(13);
+
+ if (INADDR_ANY)
+ sa.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
+ perror("bind");
+ return 2;
+ }
+
+ switch (fork()) {
+ case -1:
+ perror("fork");
+ return 3;
+ default:
+ close(s);
+ return 0;
+ case 0:
+ break;
+ }
+
+ listen(s, BACKLOG);
+
+ for (;;) {
+ b = sizeof sa;
+
+ if ((c = accept(s, (struct sockaddr *)&sa, &b)) < 0) {
+ perror("daytimed accept");
+ return 4;
+ }
+
+ if ((client = fdopen(c, "w")) == NULL) {
+ perror("daytimed fdopen");
+ return 5;
+ }
+
+ if ((t = time(NULL)) < 0) {
+ perror("daytimed time");
+ return 6;
+ }
+
+ tm = gmtime(&t);
+ fprintf(client, "%.4i-%.2i-%.2iT%.2i:%.2i:%.2iZ\n",
+ tm->tm_year + 1900,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+
+ fclose(client);
+ }
+}
+....
+
+Начинаем с создания сокета. Затем заполняем структуру `sockaddr_in` в `sa`. Обратите внимание на условное использование INADDR_ANY:
+
+[.programlisting]
+....
+if (INADDR_ANY)
+ sa.sin_addr.s_addr = htonl(INADDR_ANY);
+....
+
+Его значение равно `0`. Поскольку мы только что использовали `bzero` для всей структуры, будет избыточным снова устанавливать его в `0`. Но если мы перенесем наш код на другую систему, где INADDR_ANY, возможно, не равен нулю, нам нужно будет присвоить его `sa.sin_addr.s_addr`. Большинство современных компиляторов C достаточно умны, чтобы заметить, что INADDR_ANY — это константа. Пока она равна нулю, они оптимизируют все условное выражение из кода.
+
+После успешного вызова `bind` мы готовы стать _демоном_: используем `fork` для создания дочернего процесса. В обоих процессах, родительском и дочернем, переменная `s` является нашим сокетом. Родительскому процессу он больше не нужен, поэтому он вызывает `close`, затем возвращает `0`, чтобы сообщить своему родителю об успешном завершении.
+
+Между тем, дочерний процесс продолжает работать в фоновом режиме. Он вызывает `listen` и устанавливает размер очереди ожидания (`backlog`) равным `4`. Здесь не требуется большое значение, так как _daytime_ — это не протокол, который часто запрашивают клиенты, и, кроме того, он может мгновенно обрабатывать каждый запрос.
+
+Наконец, демон запускает бесконечный цикл, который выполняет следующие шаги:
+
+[.procedure]
+. Вызовите `accept`. Он ожидает здесь, пока клиент не свяжется с ним. В этот момент он получает новый сокет, `c`, который можно использовать для обмена данными с этим конкретным клиентом.
+. Он использует функцию C `fdopen` для преобразования сокета из низкоуровневого _дескриптора файла_ в указатель типа `FILE` в стиле C. Это позволит в дальнейшем использовать `fprintf`.
+. Он проверяет время и выводит его в формате _ISO 8601_ в «файл» `client`. Затем он использует `fclose` для закрытия файла. Это также автоматически закроет сокет.
+
+Мы можем _обобщить_ это и использовать в качестве модели для многих других серверов:
+
+.Последовательный Сервер
+image::serv.png[]
+
+Эта блок-схема подходит для _последовательных серверов_, то есть серверов, которые могут обслуживать одного клиента за раз, как это было возможно с нашим _daytime_ сервером. Это возможно только в тех случаях, когда между клиентом и сервером не происходит реального "диалога": как только сервер обнаруживает подключение клиента, он отправляет некоторые данные и закрывает соединение. Вся операция может занять наносекунды, и она завершена.
+
+Преимущество этой блок-схемы в том, что, за исключением короткого момента после того, как родительский процесс выполняет ``fork`` и до его завершения, всегда активен только один _процесс_: Наш сервер не занимает много памяти и других системных ресурсов.
+
+Обратите внимание, что мы добавили _инициализацию демона_ в нашу блок-схему. Нам не нужно было инициализировать собственный демон, но это подходящее место в потоке выполнения программы для настройки обработчиков `signal`, открытия необходимых файлов и т. д.
+
+Почти все элементы блок-схемы могут быть использованы буквально на множестве различных серверов. Элемент _serve_ является исключением. Мы рассматриваем его как _"чёрный ящик"_, то есть нечто, что вы проектируете специально для своего сервера и просто "подключаете к остальной системе."
+
+Не все протоколы настолько просты. Многие получают запрос от клиента, отвечают на него, а затем получают ещё один запрос от того же клиента. В результате, они не знают заранее, как долго будут обслуживать клиента. Такие серверы обычно запускают новый процесс для каждого клиента. Пока новый процесс обслуживает своего клиента, демон может продолжать прослушивать новые подключения.
+
+Теперь сохраните приведённый исходный код в файл [.filename]#daytimed.c# (обычно имена демонов оканчиваются буквой `d`). После компиляции попробуйте запустить его:
+
+[source, bash]
+....
+% ./daytimed
+bind: Permission denied
+%
+....
+
+Что произошло? Как вы помните, протокол _daytime_ использует порт 13. Однако все порты ниже 1024 зарезервированы для суперпользователя (в противном случае любой мог бы запустить демон, притворяясь, что обслуживает часто используемый порт, создавая угрозу безопасности).
+
+Попробуйте снова, на этот раз как суперпользователь:
+
+[source, bash]
+....
+# ./daytimed
+#
+....
+
+Что... Ничего? Давайте попробуем еще раз:
+
+[source, bash]
+....
+# ./daytimed
+
+bind: Address already in use
+#
+....
+
+Каждый порт может быть связан только одной программой одновременно. Наша первая попытка действительно была успешной: она запустила дочерний демон и завершилась без ошибок. Он продолжает работать и будет работать до тех пор, пока вы его не завершите командой kill, пока какой-либо из его системных вызовов не завершится с ошибкой или пока вы не перезагрузите систему.
+
+Хорошо, мы знаем, что он работает в фоновом режиме. Но работает ли он? Как мы можем убедиться, что это настоящий сервер _daytime_? Просто:
+
+[source, bash]
+....
+% telnet localhost 13
+
+Trying ::1...
+telnet: connect to address ::1: Connection refused
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+2001-06-19T21:04:42Z
+Connection closed by foreign host.
+%
+....
+
+telnet попробовал использовать новый IPv6, но не смог. Затем он повторил попытку с IPv4, и это удалось. Демон работает.
+
+Если у вас есть доступ к другой UNIX(R)-системе через telnet, вы можете использовать её для проверки удалённого доступа к серверу. Мой компьютер не имеет статического IP-адреса, поэтому я сделал следующее:
+
+[source, bash]
+....
+% who
+
+whizkid ttyp0 Jun 19 16:59 (216.127.220.143)
+xxx ttyp1 Jun 19 16:06 (xx.xx.xx.xx)
+% telnet 216.127.220.143 13
+
+Trying 216.127.220.143...
+Connected to r47.bfm.org.
+Escape character is '^]'.
+2001-06-19T21:31:11Z
+Connection closed by foreign host.
+%
+....
+
+Снова, это сработало. Сработает ли это с использованием доменного имени?
+
+[source, bash]
+....
+% telnet r47.bfm.org 13
+
+Trying 216.127.220.143...
+Connected to r47.bfm.org.
+Escape character is '^]'.
+2001-06-19T21:31:40Z
+Connection closed by foreign host.
+%
+....
+
+Кстати, telnet выводит сообщение _Connection closed by foreign host_ после того, как наш демон закрыл сокет. Это показывает, что использование `fclose(client);` в нашем коде действительно работает, как заявлено.
+
+[[sockets-helper-functions]]
+== Вспомогательные функции
+
+Библиотека C в FreeBSD содержит множество вспомогательных функций для программирования сокетов. Например, в нашем примере клиента мы жестко прописали IP-адрес `time.nist.gov`. Но мы не всегда знаем IP-адрес. Даже если знаем, наше программное обеспечение будет более гибким, если позволит пользователю ввести IP-адрес или даже доменное имя.
+
+[[sockets-gethostbyname]]
+=== `gethostbyname`
+
+Хотя нет возможности передать имя домена напрямую в какие-либо функции сокетов, стандартная библиотека C в FreeBSD предоставляет функции man:gethostbyname[3] и man:gethostbyname2[3], объявленные в [.filename]#netdb.h#.
+
+[.programlisting]
+....
+struct hostent * gethostbyname(const char *name);
+struct hostent * gethostbyname2(const char *name, int af);
+....
+
+Оба возвращают указатель на структуру `hostent`, содержащую много информации о домене. Для наших целей поле `h_addr_list[0]` структуры указывает на `h_length` байтов правильного адреса, уже сохранённого в _порядке байтов сети_.
+
+Это позволяет нам создать гораздо более гибкую — и гораздо более полезную — версию нашей программы daytime:
+
+[.programlisting]
+....
+/*
+ * daytime.c
+ *
+ * Programmed by G. Adam Stanislav
+ * 19 June 2001
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+int main(int argc, char *argv[]) {
+ int s, bytes;
+ struct sockaddr_in sa;
+ struct hostent *he;
+ char buf[BUFSIZ+1];
+ char *host;
+
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ return 1;
+ }
+
+ memset(&sa, '\0', sizeof(sa));
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(13);
+
+ host = (argc > 1) ? argv[1] : "time.nist.gov";
+
+ if ((he = gethostbyname(host)) == NULL) {
+ herror(host);
+ return 2;
+ }
+
+ memcpy(&sa.sin_addr, he->h_addr_list[0], he->h_length);
+
+ if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
+ perror("connect");
+ return 3;
+ }
+
+ while ((bytes = read(s, buf, BUFSIZ)) > 0)
+ write(1, buf, bytes);
+
+ close(s);
+ return 0;
+}
+....
+
+Теперь мы можем ввести доменное имя (или IP-адрес, это работает в обоих направлениях) в командной строке, и программа попытается подключиться к его серверу _daytime_. В противном случае, по умолчанию будет использоваться `time.nist.gov`. Однако даже в этом случае мы будем использовать `gethostbyname` вместо жесткого задания `192.43.244.18`. Таким образом, даже если его IP-адрес изменится в будущем, мы всё равно сможем его найти.
+
+Поскольку получение времени от локального сервера занимает практически нулевое время, вы можете запустить daytime дважды подряд: сначала для получения времени от `time.nist.gov`, а затем от вашей собственной системы. После этого вы можете сравнить результаты и увидеть, насколько точны часы вашей системы:
+
+[source, bash]
+....
+% daytime ; daytime localhost
+
+52080 01-06-20 04:02:33 50 0 0 390.2 UTC(NIST) *
+2001-06-20T04:02:35Z
+%
+....
+
+Как видно, моя система опережала время NIST на две секунды.
+
+[[sockets-getservbyname]]
+=== `getservbyname`
+
+Иногда вы можете быть не уверены, какой порт использует определённая служба. В таких случаях очень полезна функция man:getservbyname[3], также объявленная в [.filename]#netdb.h#:
+
+[.programlisting]
+....
+struct servent * getservbyname(const char *name, const char *proto);
+....
+
+Структура `servent` содержит `s_port`, в котором находится соответствующий порт, уже в _порядке байтов сети_.
+
+Если бы мы не знали правильный порт для службы _daytime_, мы могли бы найти его следующим образом:
+
+[.programlisting]
+....
+struct servent *se;
+ ...
+ if ((se = getservbyname("daytime", "tcp")) == NULL {
+ fprintf(stderr, "Cannot determine which port to use.\n");
+ return 7;
+ }
+ sa.sin_port = se->s_port;
+....
+
+Обычно порт известен. Но если вы разрабатываете новый протокол, вы можете тестировать его на неофициальном порту. Когда-нибудь вы зарегистрируете протокол и его порт (если не где-то ещё, то хотя бы в вашем [.filename]#/etc/services#, где `getservbyname` ищет). Вместо возврата ошибки в приведённом выше коде вы просто используете временный номер порта. Как только вы добавите протокол в [.filename]#/etc/services#, ваше программное обеспечение найдёт его порт без необходимости переписывать код.
+
+[[sockets-concurrent-servers]]
+== Многозадачные серверы
+
+В отличие от последовательного сервера, _многозадачный сервер_ должен иметь возможность обслуживать более одного клиента одновременно. Например, _сервер чата_ может обслуживать конкретного клиента часами — он не может ждать, пока закончит обслуживать текущего клиента, прежде чем перейти к следующему.
+
+Это требует значительных изменений в нашей блок-схеме:
+
+.Многозадачный сервер
+image::serv2.png[]
+
+Мы переместили _службу_ из _демона_ в её собственный _серверный процесс_. Однако, поскольку каждый дочерний процесс наследует все открытые файлы (а сокет обрабатывается так же, как файл), новый процесс наследует не только _"принятый дескриптор"_, т.е. сокет, возвращённый вызовом `accept`, но и _главный сокет_, т.е. тот, который был открыт главным процессом в самом начале.
+
+Однако _серверному процессу_ этот сокет не нужен, и он должен немедленно вызвать ему `close`. Аналогично, _демону_ больше не нужен _сокет, принятый вызовом accept_, и он не только должен, но и _обязан_ вызвать ему `close` — в противном случае рано или поздно закончатся доступные _файловые дескрипторы_.
+
+После завершения обслуживания _серверного процесса_ он должен закрыть _принятый сокет_. Вместо возврата к `accept`, процесс теперь завершается.
+
+В UNIX(R) процесс на самом деле не _завершается_. Вместо этого он _возвращается_ к своему родителю. Обычно родительский процесс ``ждёт`` (wait) завершения своего дочернего процесса и получает возвращаемое значение. Однако наш _демон-процесс_ не может просто остановиться и ждать. Это бы свело на нет всю цель создания дополнительных процессов. Но если он никогда не выполняет `wait`, его дочерние процессы станут _зомби_ — более не функционирующими, но всё ещё бродящими вокруг.
+
+По этой причине _демону_ необходимо установить _обработчики сигналов_ на этапе _инициализации демона_. Как минимум, должен обрабатываться сигнал SIGCHLD, чтобы демон мог удалять зомби-процессы из системы и освобождать занимаемые ими системные ресурсы.
+
+Вот почему наша блок-схема теперь содержит блок _обработки сигналов_, который не соединен с другими блоками. Кстати, многие серверы также обрабатывают SIGHUP и обычно интерпретируют его как сигнал от суперпользователя, указывающий на необходимость перечитать конфигурационные файлы. Это позволяет нам изменять настройки без необходимости завершать и перезапускать эти серверы.
diff --git a/documentation/content/ru/books/developers-handbook/sockets/_index.po b/documentation/content/ru/books/developers-handbook/sockets/_index.po
new file mode 100644
index 0000000000..7136478a70
--- /dev/null
+++ b/documentation/content/ru/books/developers-handbook/sockets/_index.po
@@ -0,0 +1,3021 @@
+# SOME DESCRIPTIVE TITLE
+# Copyright (C) YEAR The FreeBSD Project
+# This file is distributed under the same license as the FreeBSD Documentation package.
+# Vladlen Popolitov <vladlenpopolitov@list.ru>, 2025.
+msgid ""
+msgstr ""
+"Project-Id-Version: FreeBSD Documentation VERSION\n"
+"POT-Creation-Date: 2025-10-12 22:16+0300\n"
+"PO-Revision-Date: 2025-09-05 04:45+0000\n"
+"Last-Translator: Vladlen Popolitov <vladlenpopolitov@list.ru>\n"
+"Language-Team: Russian <https://translate-dev.freebsd.org/projects/"
+"documentation/booksdevelopers-handbooksockets_index/ru/>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.17\n"
+
+#. type: Yaml Front Matter Hash Value: description
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1
+#, no-wrap
+msgid "FreeBSD Sockets"
+msgstr "Сокеты FreeBSD"
+
+#. type: Yaml Front Matter Hash Value: title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1
+#, no-wrap
+msgid "Chapter 7. Sockets"
+msgstr "Глава 7. Сокеты"
+
+#. type: Title =
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:16
+#, no-wrap
+msgid "Sockets"
+msgstr "Сокеты"
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:54
+#, no-wrap
+msgid "Synopsis"
+msgstr "Обзор"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:59
+msgid ""
+"BSD sockets take interprocess communications to a new level. It is no "
+"longer necessary for the communicating processes to run on the same "
+"machine. They still _can_, but they do not have to."
+msgstr ""
+"Сокеты BSD выводят межпроцессное взаимодействие на новый уровень. Теперь "
+"взаимодействующие процессы не обязательно должны выполняться на одной "
+"машине. Они всё ещё _могут_, но не обязаны."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:62
+msgid ""
+"Not only do these processes not have to run on the same machine, they do not "
+"have to run under the same operating system. Thanks to BSD sockets, your "
+"FreeBSD software can smoothly cooperate with a program running on a "
+"Macintosh(R), another one running on a Sun(TM) workstation, yet another one "
+"running under Windows(R) 2000, all connected with an Ethernet-based local "
+"area network."
+msgstr ""
+"Не только эти процессы не обязаны выполняться на одной машине, они также "
+"могут работать под разными операционными системами. Благодаря BSD-сокетам, "
+"ваше ПО на FreeBSD может легко взаимодействовать с программой, работающей на "
+"Macintosh(R), другой — на рабочей станции Sun(TM), и ещё одной — под "
+"Windows(R) 2000, при этом все они подключены к локальной сети на основе "
+"Ethernet."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:64
+msgid ""
+"But your software can equally well cooperate with processes running in "
+"another building, or on another continent, inside a submarine, or a space "
+"shuttle."
+msgstr ""
+"Но ваше программное обеспечение может так же эффективно взаимодействовать с "
+"процессами, работающими в другом здании, на другом континенте, внутри "
+"подводной лодки или космического челнока."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:67
+msgid ""
+"It can also cooperate with processes that are not part of a computer (at "
+"least not in the strict sense of the word), but of such devices as printers, "
+"digital cameras, medical equipment. Just about anything capable of digital "
+"communications."
+msgstr ""
+"Он также может взаимодействовать с процессами, которые не являются частью "
+"компьютера (по крайней мере, не в строгом смысле этого слова), а таких "
+"устройств, как принтеры, цифровые камеры, медицинское оборудование. "
+"Практически со всем, что способно к цифровой коммуникации."
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:69
+#, no-wrap
+msgid "Networking and Diversity"
+msgstr "Сетевое взаимодействие и разнообразие"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:75
+msgid ""
+"We have already hinted on the _diversity_ of networking. Many different "
+"systems have to talk to each other. And they have to speak the same "
+"language. They also have to _understand_ the same language the same way."
+msgstr ""
+"Мы уже упоминали о _разнообразии_ сетевых технологий. Множество различных "
+"систем должны взаимодействовать друг с другом. И они должны говорить на "
+"одном языке. Также они должны _понимать_ этот язык одинаковым образом."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:80
+msgid ""
+"People often think that _body language_ is universal. But it is not. Back "
+"in my early teens, my father took me to Bulgaria. We were sitting at a "
+"table in a park in Sofia, when a vendor approached us trying to sell us some "
+"roasted almonds."
+msgstr ""
+"Часто думают, что _язык тела_ универсален. Но это не так. В ранней юности "
+"отец взял меня с собой в Болгарию. Мы сидели за столиком в парке Софии, "
+"когда к нам подошел продавец, предлагая купить жареный миндаль."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:83
+msgid ""
+"I had not learned much Bulgarian by then, so, instead of saying no, I shook "
+"my head from side to side, the \"universal\" body language for _no_. The "
+"vendor quickly started serving us some almonds."
+msgstr ""
+"Я тогда еще не знал болгарского, поэтому вместо словесного отказа я покачал "
+"головой из стороны в сторону — это «универсальный» язык тела для обозначения "
+"_нет_. Продавец тут же начал угощать нас миндалем."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:91
+msgid ""
+"I then remembered I had been told that in Bulgaria shaking your head "
+"sideways meant _yes_. Quickly, I started nodding my head up and down. The "
+"vendor noticed, took his almonds, and walked away. To an uninformed "
+"observer, I did not change the body language: I continued using the language "
+"of shaking and nodding my head. What changed was the _meaning_ of the body "
+"language. At first, the vendor and I interpreted the same language as "
+"having completely different meaning. I had to adjust my own interpretation "
+"of that language so the vendor would understand."
+msgstr ""
+"Затем я вспомнил, что мне говорили, будто в Болгарии покачивание головой из "
+"стороны в сторону означает _да_. Быстро я начал кивать головой вверх-вниз. "
+"Продавец заметил, взял свои миндалины и ушёл. Для непосвящённого наблюдателя "
+"я не изменил язык тела: я продолжал использовать движения головой — "
+"покачивание и кивание. Изменился _смысл_ языка тела. Сначала продавец и я "
+"интерпретировали одни и те же жесты как имеющие совершенно разный смысл. Мне "
+"пришлось скорректировать свою собственную интерпретацию этих жестов, чтобы "
+"продавец меня понял."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:95
+msgid ""
+"It is the same with computers: The same symbols may have different, even "
+"outright opposite meaning. Therefore, for two computers to understand each "
+"other, they must not only agree on the same _language_, but on the same "
+"_interpretation_ of the language."
+msgstr ""
+"То же самое и с компьютерами: одни и те же символы могут иметь разное, даже "
+"полностью противоположное значение. Поэтому, чтобы два компьютера понимали "
+"друг друга, они должны договориться не только об одном _языке_, но и об "
+"одном _толковании_ языка."
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:97
+#, no-wrap
+msgid "Protocols"
+msgstr "Протоколы"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:104
+msgid ""
+"While various programming languages tend to have complex syntax and use a "
+"number of multi-letter reserved words (which makes them easy for the human "
+"programmer to understand), the languages of data communications tend to be "
+"very terse. Instead of multi-byte words, they often use individual _bits_. "
+"There is a very convincing reason for it: While data travels _inside_ your "
+"computer at speeds approaching the speed of light, it often travels "
+"considerably slower between two computers."
+msgstr ""
+"В то время как различные языки программирования обычно имеют сложный "
+"синтаксис и используют множество многосимвольных зарезервированных слов (что "
+"облегчает их понимание для человека-программиста), языки передачи данных, "
+"как правило, очень лаконичны. Вместо многосимвольных слов они часто "
+"используют отдельные _биты_. Для этого есть очень убедительная причина: хотя "
+"данные внутри вашего компьютера передаются со скоростью, близкой к скорости "
+"света, между двумя компьютерами они часто передаются значительно медленнее."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:106
+msgid ""
+"As the languages used in data communications are so terse, we usually refer "
+"to them as _protocols_ rather than languages."
+msgstr ""
+"Поскольку языки, используемые в передаче данных, настолько лаконичны, мы "
+"обычно называем их _протоколами_, а не языками."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:111
+msgid ""
+"As data travels from one computer to another, it always uses more than one "
+"protocol. These protocols are _layered_. The data can be compared to the "
+"inside of an onion: You have to peel off several layers of \"skin\" to get "
+"to the data. This is best illustrated with a picture:"
+msgstr ""
+"При передаче данных от одного компьютера к другому всегда используется более "
+"одного протокола. Эти протоколы _располагаются слоями_. Данные можно "
+"сравнить с внутренней частью лука: необходимо снять несколько слоёв «кожи», "
+"чтобы добраться до данных. Это лучше всего проиллюстрировано на рисунке:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:112
+#, no-wrap
+msgid "Protocol Layers"
+msgstr "Уровни протоколов"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:113
+#, no-wrap
+msgid "layers.png"
+msgstr "layers.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:116
+msgid ""
+"In this example, we are trying to get an image from a web page we are "
+"connected to via an Ethernet."
+msgstr ""
+"В этом примере мы пытаемся получить изображение с веб-страницы, к которой "
+"подключены через Ethernet."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:119
+msgid ""
+"The image consists of raw data, which is simply a sequence of RGB values "
+"that our software can process, i.e., convert into an image and display on "
+"our monitor."
+msgstr ""
+"Изображение состоит из необработанных данных, которые представляют собой "
+"просто последовательность значений RGB, которые наше программное обеспечение "
+"может обработать, т.е. преобразовать в изображение и отобразить на нашем "
+"мониторе."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:124
+msgid ""
+"Alas, our software has no way of knowing how the raw data is organized: Is "
+"it a sequence of RGB values, or a sequence of grayscale intensities, or "
+"perhaps of CMYK encoded colors? Is the data represented by 8-bit quanta, or "
+"are they 16 bits in size, or perhaps 4 bits? How many rows and columns does "
+"the image consist of? Should certain pixels be transparent?"
+msgstr ""
+"Увы, наше программное обеспечение не может определить, как организованы "
+"сырые данные: это последовательность значений RGB, последовательность "
+"интенсивностей в градациях серого или, возможно, цвета в кодировке CMYK? "
+"Представлены ли данные 8-битными квантами, или они имеют размер 16 бит, а "
+"может быть, 4 бита? Из скольких строк и столбцов состоит изображение? Должны "
+"ли определённые пиксели быть прозрачными?"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:126
+msgid "I think you get the picture..."
+msgstr "Я думаю, вы поняли..."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:129
+msgid ""
+"To inform our software how to handle the raw data, it is encoded as a PNG "
+"file. It could be a GIF, or a JPEG, but it is a PNG."
+msgstr ""
+"Чтобы наше программное обеспечение понимало, как обрабатывать сырые данные, "
+"они кодируются в формате PNG. Это мог бы быть GIF или JPEG, но выбран PNG."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:131
+msgid "And PNG is a protocol."
+msgstr "И PNG — это протокол."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:133
+msgid ""
+"At this point, I can hear some of you yelling, _\"No, it is not! It is a "
+"file format!\"_"
+msgstr ""
+"В этот момент я слышу, как некоторые из вас кричат: _\"Нет, это не так! Это "
+"формат файла!\"_"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:138
+msgid ""
+"Well, of course it is a file format. But from the perspective of data "
+"communications, a file format is a protocol: The file structure is a "
+"_language_, a terse one at that, communicating to our _process_ how the data "
+"is organized. Ergo, it is a _protocol_."
+msgstr ""
+"Ну что ж, конечно, это формат файла. Но с точки зрения передачи данных, "
+"формат файла — это протокол: структура файла — это _язык_, причем "
+"лаконичный, сообщающий нашему _процессу_, как организованы данные. "
+"Следовательно, это _протокол_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:141
+msgid ""
+"Alas, if all we received was the PNG file, our software would be facing a "
+"serious problem: How is it supposed to know the data is representing an "
+"image, as opposed to some text, or perhaps a sound, or what not? Secondly, "
+"how is it supposed to know the image is in the PNG format as opposed to GIF, "
+"or JPEG, or some other image format?"
+msgstr ""
+"Увы, если бы мы получили только PNG-файл, наше программное обеспечение "
+"столкнулось бы с серьёзной проблемой: как ему узнать, что данные "
+"представляют изображение, а не текст, звук или что-то ещё? Во-вторых, как "
+"ему определить, что изображение сохранено в формате PNG, а не GIF, JPEG или "
+"каком-либо другом формате изображений?"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:145
+msgid ""
+"To obtain that information, we are using another protocol: HTTP. This "
+"protocol can tell us exactly that the data represents an image, and that it "
+"uses the PNG protocol. It can also tell us some other things, but let us "
+"stay focused on protocol layers here."
+msgstr ""
+"Для получения этой информации мы используем другой протокол: HTTP. Этот "
+"протокол может точно сообщить нам, что данные представляют изображение и "
+"используют протокол PNG. Он также может сообщить некоторые другие сведения, "
+"но давайте сосредоточимся на уровнях протоколов здесь."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:148
+msgid ""
+"So, now we have some data wrapped in the PNG protocol, wrapped in the HTTP "
+"protocol. How did we get it from the server?"
+msgstr ""
+"Итак, теперь у нас есть некоторые данные, упакованные в протокол PNG, "
+"который в свою очередь упакован в протокол HTTP. Как мы получили их с "
+"сервера?"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:152
+msgid ""
+"By using TCP/IP over Ethernet, that is how. Indeed, that is three more "
+"protocols. Instead of continuing inside out, I am now going to talk about "
+"Ethernet, simply because it is easier to explain the rest that way."
+msgstr ""
+"Используя TCP/IP поверх Ethernet, вот как. Действительно, это ещё три "
+"протокола. Вместо того чтобы продолжать изнутри наружу, я теперь расскажу "
+"про Ethernet, просто потому что так проще объяснить остальное."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:156
+msgid ""
+"Ethernet is an interesting system of connecting computers in a _local area "
+"network_ (LAN). Each computer has a _network interface card_ (NIC), which "
+"has a unique 48-bit ID called its _address_. No two Ethernet NICs in the "
+"world have the same address."
+msgstr ""
+"Ethernet — это интересная система соединения компьютеров в _локальной сети_ "
+"(LAN). У каждого компьютера есть _карта сетевого интерфейса_ (NIC — Network "
+"Interface Card) с уникальным 48-битным идентификатором, называемым "
+"_адресом_. Не существует двух сетевых интерфейсов Ethernet в мире с "
+"одинаковым адресом."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:162
+msgid ""
+"These NICs are all connected with each other. Whenever one computer wants "
+"to communicate with another in the same Ethernet LAN, it sends a message "
+"over the network. Every NIC sees the message. But as part of the Ethernet "
+"_protocol_, the data contains the address of the destination NIC (among "
+"other things). So, only one of all the network interface cards will pay "
+"attention to it, the rest will ignore it."
+msgstr ""
+"Эти сетевые карты соединены между собой. Когда один компьютер хочет "
+"связаться с другим в той же локальной сети Ethernet, он отправляет сообщение "
+"по сети. Каждая сетевая карта видит это сообщение. Однако, согласно "
+"_протоколу_ Ethernet, данные содержат адрес сетевой карты назначения (среди "
+"прочего). Таким образом, только одна из всех сетевых карт обратит на него "
+"внимание, остальные проигнорируют его."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:166
+msgid ""
+"But not all computers are connected to the same network. Just because we "
+"have received the data over our Ethernet does not mean it originated in our "
+"own local area network. It could have come to us from some other network "
+"(which may not even be Ethernet based) connected with our own network via "
+"the Internet."
+msgstr ""
+"Но не все компьютеры подключены к одной сети. Тот факт, что мы получили "
+"данные через наш Ethernet, не означает, что они возникли в нашей локальной "
+"сети. Они могли попасть к нам из другой сети (которая может быть даже не на "
+"основе Ethernet), соединённой с нашей сетью через Интернет."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:170
+msgid ""
+"All data is transferred over the Internet using IP, which stands for "
+"_Internet Protocol_. Its basic role is to let us know where in the world "
+"the data has arrived from, and where it is supposed to go to. It does not "
+"_guarantee_ we will receive the data, only that we will know where it came "
+"from _if_ we do receive it."
+msgstr ""
+"Все данные передаются через Интернет с использованием IP, что означает "
+"_Internet Protocol_. Его основная роль — сообщать нам, откуда в мире пришли "
+"данные и куда они должны быть направлены. Он не _гарантирует_, что мы "
+"получим данные, только что мы узнаем, откуда они пришли, _если_ мы их "
+"получим."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:173
+msgid ""
+"Even if we do receive the data, IP does not guarantee we will receive "
+"various chunks of data in the same order the other computer has sent it to "
+"us. So, we can receive the center of our image before we receive the upper "
+"left corner and after the lower right, for example."
+msgstr ""
+"Даже если мы получим данные, IP не гарантирует, что различные фрагменты "
+"данных придут в том же порядке, в котором их отправил другой компьютер. "
+"Например, мы можем получить центр нашего изображения до того, как получим "
+"его верхний левый угол, а после — нижний правый."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:175
+msgid ""
+"It is TCP (_Transmission Control Protocol_) that asks the sender to resend "
+"any lost data and that places it all into the proper order."
+msgstr ""
+"Это TCP (_Transmission Control Protocol_), который запрашивает у отправителя "
+"повторную отправку потерянных данных и располагает их в правильном порядке."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:178
+msgid ""
+"All in all, it took _five_ different protocols for one computer to "
+"communicate to another what an image looks like. We received the data "
+"wrapped into the PNG protocol, which was wrapped into the HTTP protocol, "
+"which was wrapped into the TCP protocol, which was wrapped into the IP "
+"protocol, which was wrapped into the Ethernet protocol."
+msgstr ""
+"В итоге потребовалось _пять_ различных протоколов, чтобы один компьютер мог "
+"сообщить другому, как выглядит изображение. Мы получили данные, упакованные "
+"в протокол PNG, который был упакован в протокол HTTP, который был упакован в "
+"протокол TCP, который был упакован в протокол IP, который был упакован в "
+"протокол Ethernet."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:182
+msgid ""
+"Oh, and by the way, there probably were several other protocols involved "
+"somewhere on the way. For example, if our LAN was connected to the Internet "
+"through a dial-up call, it used the PPP protocol over the modem which used "
+"one (or several) of the various modem protocols, et cetera, et cetera, et "
+"cetera..."
+msgstr ""
+"О, и кстати, вероятно, на пути были задействованы и несколько других "
+"протоколов. Например, если наша локальная сеть была подключена к Интернету "
+"через дозвон, то использовался протокол PPP над модемом, который, в свою "
+"очередь, использовал один (или несколько) из различных модемных протоколов, "
+"и так далее, и так далее, и так далее..."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:184
+msgid ""
+"As a developer you should be asking by now, _\"How am I supposed to handle "
+"it all?\"_"
+msgstr ""
+"Как разработчик, вы уже должны задаваться вопросом: _\"Как я должен со всем "
+"этим справляться?\"_"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:189
+msgid ""
+"Luckily for you, you are _not_ supposed to handle it all. You _are_ "
+"supposed to handle some of it, but not all of it. Specifically, you need "
+"not worry about the physical connection (in our case Ethernet and possibly "
+"PPP, etc). Nor do you need to handle the Internet Protocol, or the "
+"Transmission Control Protocol."
+msgstr ""
+"К счастью для вас, вам _не_ нужно разбираться во всём этом. Вам _придётся_ "
+"разобраться в некоторой части, но не во всей. В частности, вам не нужно "
+"беспокоиться о физическом подключении (в нашем случае Ethernet и, возможно, "
+"PPP и т.д.). Также вам не нужно разбираться с протоколом IP или протоколом "
+"TCP."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:192
+msgid ""
+"In other words, you do not have to do anything to receive the data from the "
+"other computer. Well, you do have to _ask_ for it, but that is almost as "
+"simple as opening a file."
+msgstr ""
+"Другими словами, вам не нужно ничего делать, чтобы получить данные с другого "
+"компьютера. Ну, разве что _попросить_ их, но это почти так же просто, как "
+"открыть файл."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:195
+msgid ""
+"Once you have received the data, it is up to you to figure out what to do "
+"with it. In our case, you would need to understand the HTTP protocol and "
+"the PNG file structure."
+msgstr ""
+"Получив данные, вам предстоит решить, что с ними делать. В нашем случае "
+"потребуется понимание протокола HTTP и структуры файла PNG."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:199
+msgid ""
+"To use an analogy, all the internetworking protocols become a gray area: Not "
+"so much because we do not understand how it works, but because we are no "
+"longer concerned about it. The sockets interface takes care of this gray "
+"area for us:"
+msgstr ""
+"Используя аналогию, все межсетевые протоколы становятся серой зоной: не "
+"столько потому, что мы не понимаем, как они работают, а потому, что нас это "
+"больше не беспокоит. Интерфейс сокетов берёт на себя заботу об этой серой "
+"зоне:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:200
+#, no-wrap
+msgid "Sockets Covered Protocol Layers"
+msgstr "Уровни протоколов, покрываемые сокетами"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:201
+#, no-wrap
+msgid "slayers.png"
+msgstr "slayers.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:204
+msgid ""
+"We only need to understand any protocols that tell us how to _interpret the "
+"data_, not how to _receive_ it from another process, nor how to _send_ it to "
+"another process."
+msgstr ""
+"Нам нужно понимать только те протоколы, которые говорят нам, как "
+"_интерпретировать данные_, а не как _получать_ их от другого процесса или "
+"как _передавать_ их другому процессу."
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:206
+#, no-wrap
+msgid "The Sockets Model"
+msgstr "Модель сокетов"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:211
+msgid ""
+"BSD sockets are built on the basic UNIX(R) model: _Everything is a file._ In "
+"our example, then, sockets would let us receive an _HTTP file_, so to "
+"speak. It would then be up to us to extract the _PNG file_ from it."
+msgstr ""
+"Сокеты BSD построены по базовой модели UNIX(R): _Все является файлом._ Таким "
+"образом, в нашем примере сокеты позволят нам получить, образно говоря, _HTTP-"
+"файл_. Затем нам предстоит извлечь из него _PNG-файл_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:214
+msgid ""
+"Due to the complexity of internetworking, we cannot just use the `open` "
+"system call, or the `open()` C function. Instead, we need to take several "
+"steps to \"opening\" a socket."
+msgstr ""
+"Из-за сложности межсетевого взаимодействия мы не можем просто использовать "
+"системный вызов `open` или функцию `open()` в языке C. Вместо этого "
+"необходимо выполнить несколько шагов для \"открытия\" сокета."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:217
+msgid ""
+"Once we do, however, we can start treating the _socket_ the same way we "
+"treat any _file descriptor_: We can `read` from it, `write` to it, `pipe` "
+"it, and, eventually, `close` it."
+msgstr ""
+"Однако, как только мы это сделаем, мы можем начать обращаться с _сокетом_ "
+"так же, как и с любым _файловым дескриптором_: мы можем `читать` из него, "
+"`писать` в него, передавать его через `канал` и, в конечном итоге, "
+"`закрывать` его."
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:219
+#, no-wrap
+msgid "Essential Socket Functions"
+msgstr "Основные функции сокетов"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:223
+msgid ""
+"While FreeBSD offers different functions to work with sockets, we only "
+"_need_ four to \"open\" a socket. And in some cases we only need two."
+msgstr ""
+"В то время как FreeBSD предлагает различные функции для работы с сокетами, "
+"нам _требуется_ только четыре, чтобы \"открыть\" сокет. А в некоторых "
+"случаях достаточно двух."
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:225
+#, no-wrap
+msgid "The Client-Server Difference"
+msgstr "Разница между клиентом и сервером"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:228
+msgid ""
+"Typically, one of the ends of a socket-based data communication is a "
+"_server_, the other is a _client_."
+msgstr ""
+"Обычно одним из концов связи на основе сокетов является _сервер_, а другой — "
+"_клиент_."
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:230
+#, no-wrap
+msgid "The Common Elements"
+msgstr "Общие элементы"
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:233
+#, no-wrap
+msgid "`socket`"
+msgstr "`socket`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:237
+msgid ""
+"The one function used by both, clients and servers, is man:socket[2]. It is "
+"declared this way:"
+msgstr ""
+"Функция, используемая как клиентами, так и серверами, это man:socket[2]. Она "
+"объявляется следующим образом:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:241
+#, no-wrap
+msgid "int socket(int domain, int type, int protocol);\n"
+msgstr "int socket(int domain, int type, int protocol);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:246
+msgid ""
+"The return value is of the same type as that of `open`, an integer. FreeBSD "
+"allocates its value from the same pool as that of file handles. That is "
+"what allows sockets to be treated the same way as files."
+msgstr ""
+"Возвращаемое значение имеет тот же тип, что и у `open`, целое число. FreeBSD "
+"выделяет его значение из того же пула, что и дескрипторы файлов. Это "
+"позволяет обрабатывать сокеты так же, как файлы."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:250
+msgid ""
+"The `domain` argument tells the system what _protocol family_ you want it to "
+"use. Many of them exist, some are vendor specific, others are very common. "
+"They are declared in [.filename]#sys/socket.h#."
+msgstr ""
+"Аргумент `domain` указывает системе, какое _семейство протоколов_ следует "
+"использовать. Существует множество семейств, некоторые из них специфичны для "
+"определённых поставщиков, другие широко распространены. Они объявлены в "
+"[.filename]#sys/socket.h#."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:252
+msgid "Use `PF_INET` for UDP, TCP and other Internet protocols (IPv4)."
+msgstr ""
+"Используйте `PF_INET` для UDP, TCP и других интернет-протоколов (IPv4)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:256
+msgid ""
+"Five values are defined for the `type` argument, again, in [.filename]#sys/"
+"socket.h#. All of them start with \"`SOCK_`\". The most common one is "
+"`SOCK_STREAM`, which tells the system you are asking for a _reliable stream "
+"delivery service_ (which is TCP when used with `PF_INET`)."
+msgstr ""
+"Для аргумента `type` определено пять значений, также указанных в "
+"[.filename]#sys/socket.h#. Все они начинаются с \"`SOCK_`\". Наиболее "
+"распространённое — `SOCK_STREAM`, которое указывает системе, что "
+"запрашивается _надёжный сервис потоковой доставки_ (это TCP при "
+"использовании с `PF_INET`)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:258
+msgid ""
+"If you asked for `SOCK_DGRAM`, you would be requesting a _connectionless "
+"datagram delivery service_ (in our case, UDP)."
+msgstr ""
+"Если бы вы запросили `SOCK_DGRAM`, вы бы запросили _сервис доставки "
+"датаграмм без установления соединения_ (в нашем случае, UDP)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:260
+msgid ""
+"If you wanted to be in charge of the low-level protocols (such as IP), or "
+"even network interfaces (e.g., the Ethernet), you would need to specify "
+"`SOCK_RAW`."
+msgstr ""
+"Если вы хотите управлять низкоуровневыми протоколами (такими как IP) или "
+"даже сетевыми интерфейсами (например, Ethernet), вам потребуется указать "
+"`SOCK_RAW`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:263
+msgid ""
+"Finally, the `protocol` argument depends on the previous two arguments, and "
+"is not always meaningful. In that case, use `0` for its value."
+msgstr ""
+"Наконец, аргумент `protocol` зависит от двух предыдущих аргументов и не "
+"всегда имеет смысл. В таком случае используйте значение `0`."
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:265
+#, no-wrap
+msgid "The Unconnected Socket"
+msgstr "Неподключенный сокет"
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:269
+msgid ""
+"Nowhere, in the `socket` function have we specified to what other system we "
+"should be connected. Our newly created socket remains _unconnected_."
+msgstr ""
+"Нигде в функции `socket` мы не указали, к какой другой системе должны быть "
+"подключены. Наш только что созданный сокет остаётся _неподключённым_."
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:272
+msgid ""
+"This is on purpose: To use a telephone analogy, we have just attached a "
+"modem to the phone line. We have neither told the modem to make a call, nor "
+"to answer if the phone rings."
+msgstr ""
+"Это сделано намеренно: если проводить аналогию с телефоном, мы только что "
+"подключили модем к телефонной линии. Мы не сказали модему совершить звонок "
+"или ответить, если телефон зазвонит."
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:275
+#, no-wrap
+msgid "`sockaddr`"
+msgstr "`sockaddr`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:280
+msgid ""
+"Various functions of the sockets family expect the address of (or pointer "
+"to, to use C terminology) a small area of the memory. The various C "
+"declarations in the [.filename]#sys/socket.h# refer to it as `struct "
+"sockaddr`. This structure is declared in the same file:"
+msgstr ""
+"Различные функции семейства сокетов ожидают адрес (или указатель, если "
+"использовать терминологию языка C) небольшой области памяти. Различные "
+"объявления на языке C в файле [.filename]#sys/socket.h# ссылаются на неё как "
+"на `struct sockaddr`. Эта структура объявлена в том же файле:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:293
+#, no-wrap
+msgid ""
+"/*\n"
+" * Structure used by kernel to store most\n"
+" * addresses.\n"
+" */\n"
+"struct sockaddr {\n"
+"\tunsigned char\tsa_len;\t\t/* total length */\n"
+"\tsa_family_t\tsa_family;\t/* address family */\n"
+"\tchar\t\tsa_data[14];\t/* actually longer; address value */\n"
+"};\n"
+"#define\tSOCK_MAXADDRLEN\t255\t\t/* longest possible addresses */\n"
+msgstr ""
+"/*\n"
+" * Structure used by kernel to store most\n"
+" * addresses.\n"
+" */\n"
+"struct sockaddr {\n"
+"\tunsigned char\tsa_len;\t\t/* total length */\n"
+"\tsa_family_t\tsa_family;\t/* address family */\n"
+"\tchar\t\tsa_data[14];\t/* actually longer; address value */\n"
+"};\n"
+"#define\tSOCK_MAXADDRLEN\t255\t\t/* longest possible addresses */\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:297
+msgid ""
+"Please note the _vagueness_ with which the `sa_data` field is declared, just "
+"as an array of `14` bytes, with the comment hinting there can be more than "
+"`14` of them."
+msgstr ""
+"Обратите внимание на _неопределённость_, с которой объявлено поле `sa_data` "
+"— просто как массив из `14` байт, с комментарием, намекающим, что их может "
+"быть больше `14`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:300
+msgid ""
+"This vagueness is quite deliberate. Sockets is a very powerful interface. "
+"While most people perhaps think of it as nothing more than the Internet "
+"interface-and most applications probably use it for that nowadays-sockets "
+"can be used for just about _any_ kind of interprocess communications, of "
+"which the Internet (or, more precisely, IP) is only one."
+msgstr ""
+"Эта неопределенность вполне преднамеренна. Сокеты — это очень мощный "
+"интерфейс. Хотя большинство людей, возможно, считают их не более чем "
+"интерфейсом для Интернета — и большинство приложений, вероятно, используют "
+"их именно для этого в наши дни — сокеты могут быть использованы практически "
+"для _любого_ вида межпроцессного взаимодействия, из которых Интернет (или, "
+"точнее, IP) — лишь один из них."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:303
+msgid ""
+"The [.filename]#sys/socket.h# refers to the various types of protocols "
+"sockets will handle as _address families_, and lists them right before the "
+"definition of `sockaddr`:"
+msgstr ""
+"[.filename]#sys/socket.h# ссылается на различные типы протоколов, с которыми "
+"работают сокеты, как на _семейства адресов_, и перечисляет их "
+"непосредственно перед определением `sockaddr`:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:352
+#, no-wrap
+msgid ""
+"/*\n"
+" * Address families.\n"
+" */\n"
+"#define\tAF_UNSPEC\t0\t\t/* unspecified */\n"
+"#define\tAF_LOCAL\t1\t\t/* local to host (pipes, portals) */\n"
+"#define\tAF_UNIX\t\tAF_LOCAL\t/* backward compatibility */\n"
+"#define\tAF_INET\t\t2\t\t/* internetwork: UDP, TCP, etc. */\n"
+"#define\tAF_IMPLINK\t3\t\t/* arpanet imp addresses */\n"
+"#define\tAF_PUP\t\t4\t\t/* pup protocols: e.g. BSP */\n"
+"#define\tAF_CHAOS\t5\t\t/* mit CHAOS protocols */\n"
+"#define\tAF_NS\t\t6\t\t/* XEROX NS protocols */\n"
+"#define\tAF_ISO\t\t7\t\t/* ISO protocols */\n"
+"#define\tAF_OSI\t\tAF_ISO\n"
+"#define\tAF_ECMA\t\t8\t\t/* European computer manufacturers */\n"
+"#define\tAF_DATAKIT\t9\t\t/* datakit protocols */\n"
+"#define\tAF_CCITT\t10\t\t/* CCITT protocols, X.25 etc */\n"
+"#define\tAF_SNA\t\t11\t\t/* IBM SNA */\n"
+"#define AF_DECnet\t12\t\t/* DECnet */\n"
+"#define AF_DLI\t\t13\t\t/* DEC Direct data link interface */\n"
+"#define AF_LAT\t\t14\t\t/* LAT */\n"
+"#define\tAF_HYLINK\t15\t\t/* NSC Hyperchannel */\n"
+"#define\tAF_APPLETALK\t16\t\t/* Apple Talk */\n"
+"#define\tAF_ROUTE\t17\t\t/* Internal Routing Protocol */\n"
+"#define\tAF_LINK\t\t18\t\t/* Link layer interface */\n"
+"#define\tpseudo_AF_XTP\t19\t\t/* eXpress Transfer Protocol (no AF) */\n"
+"#define\tAF_COIP\t\t20\t\t/* connection-oriented IP, aka ST II */\n"
+"#define\tAF_CNT\t\t21\t\t/* Computer Network Technology */\n"
+"#define pseudo_AF_RTIP\t22\t\t/* Help Identify RTIP packets */\n"
+"#define\tAF_IPX\t\t23\t\t/* Novell Internet Protocol */\n"
+"#define\tAF_SIP\t\t24\t\t/* Simple Internet Protocol */\n"
+"#define\tpseudo_AF_PIP\t25\t\t/* Help Identify PIP packets */\n"
+"#define\tAF_ISDN\t\t26\t\t/* Integrated Services Digital Network*/\n"
+"#define\tAF_E164\t\tAF_ISDN\t\t/* CCITT E.164 recommendation */\n"
+"#define\tpseudo_AF_KEY\t27\t\t/* Internal key-management function */\n"
+"#define\tAF_INET6\t28\t\t/* IPv6 */\n"
+"#define\tAF_NATM\t\t29\t\t/* native ATM access */\n"
+"#define\tAF_ATM\t\t30\t\t/* ATM */\n"
+"#define pseudo_AF_HDRCMPLT 31\t\t/* Used by BPF to not rewrite headers\n"
+"\t\t\t\t\t * in interface output routine\n"
+"\t\t\t\t\t */\n"
+"#define\tAF_NETGRAPH\t32\t\t/* Netgraph sockets */\n"
+"#define\tAF_SLOW\t\t33\t\t/* 802.3ad slow protocol */\n"
+"#define\tAF_SCLUSTER\t34\t\t/* Sitara cluster protocol */\n"
+"#define\tAF_ARP\t\t35\n"
+"#define\tAF_BLUETOOTH\t36\t\t/* Bluetooth sockets */\n"
+"#define\tAF_MAX\t\t37\n"
+msgstr ""
+"/*\n"
+" * Address families.\n"
+" */\n"
+"#define\tAF_UNSPEC\t0\t\t/* unspecified */\n"
+"#define\tAF_LOCAL\t1\t\t/* local to host (pipes, portals) */\n"
+"#define\tAF_UNIX\t\tAF_LOCAL\t/* backward compatibility */\n"
+"#define\tAF_INET\t\t2\t\t/* internetwork: UDP, TCP, etc. */\n"
+"#define\tAF_IMPLINK\t3\t\t/* arpanet imp addresses */\n"
+"#define\tAF_PUP\t\t4\t\t/* pup protocols: e.g. BSP */\n"
+"#define\tAF_CHAOS\t5\t\t/* mit CHAOS protocols */\n"
+"#define\tAF_NS\t\t6\t\t/* XEROX NS protocols */\n"
+"#define\tAF_ISO\t\t7\t\t/* ISO protocols */\n"
+"#define\tAF_OSI\t\tAF_ISO\n"
+"#define\tAF_ECMA\t\t8\t\t/* European computer manufacturers */\n"
+"#define\tAF_DATAKIT\t9\t\t/* datakit protocols */\n"
+"#define\tAF_CCITT\t10\t\t/* CCITT protocols, X.25 etc */\n"
+"#define\tAF_SNA\t\t11\t\t/* IBM SNA */\n"
+"#define AF_DECnet\t12\t\t/* DECnet */\n"
+"#define AF_DLI\t\t13\t\t/* DEC Direct data link interface */\n"
+"#define AF_LAT\t\t14\t\t/* LAT */\n"
+"#define\tAF_HYLINK\t15\t\t/* NSC Hyperchannel */\n"
+"#define\tAF_APPLETALK\t16\t\t/* Apple Talk */\n"
+"#define\tAF_ROUTE\t17\t\t/* Internal Routing Protocol */\n"
+"#define\tAF_LINK\t\t18\t\t/* Link layer interface */\n"
+"#define\tpseudo_AF_XTP\t19\t\t/* eXpress Transfer Protocol (no AF) */\n"
+"#define\tAF_COIP\t\t20\t\t/* connection-oriented IP, aka ST II */\n"
+"#define\tAF_CNT\t\t21\t\t/* Computer Network Technology */\n"
+"#define pseudo_AF_RTIP\t22\t\t/* Help Identify RTIP packets */\n"
+"#define\tAF_IPX\t\t23\t\t/* Novell Internet Protocol */\n"
+"#define\tAF_SIP\t\t24\t\t/* Simple Internet Protocol */\n"
+"#define\tpseudo_AF_PIP\t25\t\t/* Help Identify PIP packets */\n"
+"#define\tAF_ISDN\t\t26\t\t/* Integrated Services Digital Network*/\n"
+"#define\tAF_E164\t\tAF_ISDN\t\t/* CCITT E.164 recommendation */\n"
+"#define\tpseudo_AF_KEY\t27\t\t/* Internal key-management function */\n"
+"#define\tAF_INET6\t28\t\t/* IPv6 */\n"
+"#define\tAF_NATM\t\t29\t\t/* native ATM access */\n"
+"#define\tAF_ATM\t\t30\t\t/* ATM */\n"
+"#define pseudo_AF_HDRCMPLT 31\t\t/* Used by BPF to not rewrite headers\n"
+"\t\t\t\t\t * in interface output routine\n"
+"\t\t\t\t\t */\n"
+"#define\tAF_NETGRAPH\t32\t\t/* Netgraph sockets */\n"
+"#define\tAF_SLOW\t\t33\t\t/* 802.3ad slow protocol */\n"
+"#define\tAF_SCLUSTER\t34\t\t/* Sitara cluster protocol */\n"
+"#define\tAF_ARP\t\t35\n"
+"#define\tAF_BLUETOOTH\t36\t\t/* Bluetooth sockets */\n"
+"#define\tAF_MAX\t\t37\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:356
+msgid "The one used for IP is AF_INET. It is a symbol for the constant `2`."
+msgstr "Используемый для IP — это AF_INET. Это символ для константы `2`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:358
+msgid ""
+"It is the _address family_ listed in the `sa_family` field of `sockaddr` "
+"that decides how exactly the vaguely named bytes of `sa_data` will be used."
+msgstr ""
+"Это _семейство адресов_, указанное в поле `sa_family` структуры `sockaddr`, "
+"определяет, как именно будут использоваться нечетко названные байты "
+"`sa_data`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:360
+msgid ""
+"Specifically, whenever the _address family_ is AF_INET, we can use `struct "
+"sockaddr_in` found in [.filename]#netinet/in.h#, wherever `sockaddr` is "
+"expected:"
+msgstr ""
+"В частности, когда _семейство адресов_ — AF_INET, можно использовать `struct "
+"sockaddr_in` из [.filename]#netinet/in.h# везде, где ожидается `sockaddr`:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:373
+#, no-wrap
+msgid ""
+"/*\n"
+" * Socket address, internet style.\n"
+" */\n"
+"struct sockaddr_in {\n"
+"\tuint8_t\t\tsin_len;\n"
+"\tsa_family_t\tsin_family;\n"
+"\tin_port_t\tsin_port;\n"
+"\tstruct\tin_addr sin_addr;\n"
+"\tchar\tsin_zero[8];\n"
+"};\n"
+msgstr ""
+"/*\n"
+" * Socket address, internet style.\n"
+" */\n"
+"struct sockaddr_in {\n"
+"\tuint8_t\t\tsin_len;\n"
+"\tsa_family_t\tsin_family;\n"
+"\tin_port_t\tsin_port;\n"
+"\tstruct\tin_addr sin_addr;\n"
+"\tchar\tsin_zero[8];\n"
+"};\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:376
+msgid "We can visualize its organization this way:"
+msgstr "Мы можем визуализировать его организацию следующим образом:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:377
+#, no-wrap
+msgid "sockaddr_in structure"
+msgstr "Структура `sockaddr_in`"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:378
+#, no-wrap
+msgid "sain.png"
+msgstr "sain.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:381
+msgid ""
+"The three important fields are `sin_family`, which is byte 1 of the "
+"structure, `sin_port`, a 16-bit value found in bytes 2 and 3, and "
+"`sin_addr`, a 32-bit integer representation of the IP address, stored in "
+"bytes 4-7."
+msgstr ""
+"Три важных поля — это `sin_family`, которое находится в байте 1 структуры, "
+"`sin_port`, 16-битное значение, расположенное в байтах 2 и 3, и `sin_addr`, "
+"32-битное целочисленное представление IP-адреса, хранящееся в байтах 4–7."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:387
+msgid ""
+"Now, let us try to fill it out. Let us assume we are trying to write a "
+"client for the _daytime_ protocol, which simply states that its server will "
+"write a text string representing the current date and time to port 13. We "
+"want to use TCP/IP, so we need to specify `AF_INET` in the address family "
+"field. `AF_INET` is defined as `2`. Let us use the IP address of "
+"`192.43.244.18`, which is the time server of US federal government "
+"(`time.nist.gov`)."
+msgstr ""
+"Теперь попробуем заполнить его. Предположим, мы пытаемся написать клиент для "
+"протокола _daytime_, который просто указывает, что его сервер записывает "
+"текстовую строку с текущей датой и временем в порт 13. Мы хотим использовать "
+"TCP/IP, поэтому нам нужно указать `AF_INET` в поле семейства адресов. "
+"`AF_INET` определен как `2`. Давайте используем IP-адрес `192.43.244.18`, "
+"который является сервером времени федерального правительства США "
+"(`time.nist.gov`)."
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:388
+#, no-wrap
+msgid "Specific example of sockaddr_in"
+msgstr "Конкретный пример sockaddr_in"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:389
+#, no-wrap
+msgid "sainfill.png"
+msgstr "sainfill.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:392
+msgid ""
+"By the way the `sin_addr` field is declared as being of the `struct in_addr` "
+"type, which is defined in [.filename]#netinet/in.h#:"
+msgstr ""
+"Кстати, поле `sin_addr` объявлено как имеющее тип `struct in_addr`, который "
+"определён в [.filename]#netinet/in.h#:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:401
+#, no-wrap
+msgid ""
+"/*\n"
+" * Internet address (a structure for historical reasons)\n"
+" */\n"
+"struct in_addr {\n"
+"\tin_addr_t s_addr;\n"
+"};\n"
+msgstr ""
+"/*\n"
+" * Internet address (a structure for historical reasons)\n"
+" */\n"
+"struct in_addr {\n"
+"\tin_addr_t s_addr;\n"
+"};\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:404
+msgid "In addition, `in_addr_t` is a 32-bit integer."
+msgstr "В дополнение, `in_addr_t` является 32-битным целым числом."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:406
+msgid ""
+"The `192.43.244.18` is just a convenient notation of expressing a 32-bit "
+"integer by listing all of its 8-bit bytes, starting with the _most "
+"significant_ one."
+msgstr ""
+"`192.43.244.18` — это просто удобная форма записи 32-битного целого числа, в "
+"которой перечисляются все его 8-битные байты, начиная с _старшего_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:410
+msgid ""
+"So far, we have viewed `sockaddr` as an abstraction. Our computer does not "
+"store `short` integers as a single 16-bit entity, but as a sequence of 2 "
+"bytes. Similarly, it stores 32-bit integers as a sequence of 4 bytes."
+msgstr ""
+"До сих пор мы рассматривали `sockaddr` как абстракцию. Наш компьютер не "
+"хранит `short` целые числа как единую 16-битную сущность, а как "
+"последовательность 2 байт. Аналогично, он хранит 32-битные целые числа как "
+"последовательность 4 байт."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:412
+msgid "Suppose we coded something like this:"
+msgstr "Предположим, мы написали что-то вроде этого:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:418
+#, no-wrap
+msgid ""
+"sa.sin_family = AF_INET;\n"
+"sa.sin_port = 13;\n"
+"sa.sin_addr.s_addr = (((((192 << 8) | 43) << 8) | 244) << 8) | 18;\n"
+msgstr ""
+"sa.sin_family = AF_INET;\n"
+"sa.sin_port = 13;\n"
+"sa.sin_addr.s_addr = (((((192 << 8) | 43) << 8) | 244) << 8) | 18;\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:421
+msgid "What would the result look like?"
+msgstr "Как будет выглядеть результат?"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:424
+msgid ""
+"Well, that depends, of course. On a Pentium(R), or other x86, based "
+"computer, it would look like this:"
+msgstr ""
+"Ну, это, конечно, зависит от многого. На компьютере с процессором Pentium(R) "
+"или другим на базе x86 это будет выглядеть так:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:425
+#, no-wrap
+msgid "sockaddr_in on an Intel system"
+msgstr "`sockaddr_in` в системе с архитектурой Intel"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:426
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:472
+#, no-wrap
+msgid "sainlsb.png"
+msgstr "sainlsb.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:429
+msgid "On a different system, it might look like this:"
+msgstr "На другой системе это может выглядеть так:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:430
+#, no-wrap
+msgid "sockaddr_in on an MSB system"
+msgstr "`sockaddr_in` в системе с порядком байтов от старшего к младшему"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:431
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:477
+#, no-wrap
+msgid "sainmsb.png"
+msgstr "sainmsb.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:435
+msgid ""
+"And on a PDP it might look different yet. But the above two are the most "
+"common ways in use today."
+msgstr ""
+"И на PDP это может выглядеть иначе. Однако два приведённых выше варианта "
+"являются наиболее распространёнными на сегодняшний день."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:439
+msgid ""
+"Ordinarily, wanting to write portable code, programmers pretend that these "
+"differences do not exist. And they get away with it (except when they code "
+"in assembly language). Alas, you cannot get away with it that easily when "
+"coding for sockets."
+msgstr ""
+"Обычно, стремясь писать переносимый код, программисты делают вид, что этих "
+"различий не существует. И им это сходит с рук (за исключением случаев, когда "
+"они пишут на ассемблере). Увы, при программировании сокетов так легко "
+"отделаться не получится."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:441
+msgid "Why?"
+msgstr "Почему?"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:443
+msgid ""
+"Because when communicating with another computer, you usually do not know "
+"whether it stores data _most significant byte_ (MSB) or _least significant "
+"byte_ (LSB) first."
+msgstr ""
+"Потому что при обмене данными с другим компьютером вы обычно не знаете, "
+"хранит ли он данные, начиная со _старшего байта_ (MSB) или с _младшего "
+"байта_ (LSB)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:445
+msgid "You might be wondering, _\"So, will sockets not handle it for me?\"_"
+msgstr ""
+"Вы можете задаться вопросом: _\"Значит, сокеты не будут это делать за меня?"
+"\"_"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:447
+msgid "It will not."
+msgstr "Не будут."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:450
+msgid ""
+"While that answer may surprise you at first, remember that the general "
+"sockets interface only understands the `sa_len` and `sa_family` fields of "
+"the `sockaddr` structure. You do not have to worry about the byte order "
+"there (of course, on FreeBSD `sa_family` is only 1 byte anyway, but many "
+"other UNIX(R) systems do not have `sa_len` and use 2 bytes for `sa_family`, "
+"and expect the data in whatever order is native to the computer)."
+msgstr ""
+"Хотя этот ответ может сначала вас удивить, помните, что общий интерфейс "
+"сокетов понимает только поля `sa_len` и `sa_family` структуры `sockaddr`. "
+"Вам не нужно беспокоиться о порядке байтов (конечно, в FreeBSD `sa_family` "
+"занимает всего 1 байт, но многие другие UNIX(R)-системы не имеют `sa_len` и "
+"используют 2 байта для `sa_family`, ожидая данные в том порядке, который "
+"является родным для компьютера)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:453
+msgid ""
+"But the rest of the data is just `sa_data[14]` as far as sockets goes. "
+"Depending on the _address family_, sockets just forwards that data to its "
+"destination."
+msgstr ""
+"Но остальные данные — это просто `sa_data[14]` с точки зрения сокетов. В "
+"зависимости от _семейства адресов_ сокеты просто передают эти данные по "
+"назначению."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:458
+msgid ""
+"Indeed, when we enter a port number, it is because we want the other "
+"computer to know what service we are asking for. And, when we are the "
+"server, we read the port number so we know what service the other computer "
+"is expecting from us. Either way, sockets only has to forward the port "
+"number as data. It does not interpret it in any way."
+msgstr ""
+"Действительно, когда мы указываем номер порта, это делается для того, чтобы "
+"другая компьютерная система знала, какую службу мы запрашиваем. И, когда мы "
+"выступаем в роли сервера, мы считываем номер порта, чтобы понять, какую "
+"службу ожидает от нас другая система. В любом случае, сокетам нужно лишь "
+"передать номер порта в качестве данных. Они никак его не интерпретируют."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:461
+msgid ""
+"Similarly, we enter the IP address to tell everyone on the way where to send "
+"our data to. Sockets, again, only forwards it as data."
+msgstr ""
+"Аналогично, мы указываем IP-адрес, чтобы сообщить всем на пути, куда "
+"отправлять наши данные. Сокеты, опять же, просто пересылают их как данные."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:463
+msgid ""
+"That is why, we (the _programmers_, not the _sockets_) have to distinguish "
+"between the byte order used by our computer and a conventional byte order to "
+"send the data in to the other computer."
+msgstr ""
+"Вот почему мы (программисты, а не сокеты) должны различать порядок байтов, "
+"используемый нашим компьютером, и условный порядок байтов для отправки "
+"данных на другой компьютер."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:465
+msgid ""
+"We will call the byte order our computer uses the _host byte order_, or just "
+"the _host order_."
+msgstr ""
+"Мы будем называть порядок байтов, который использует наш компьютер, "
+"_порядком байтов хоста_ или просто _хост-порядком_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:468
+msgid ""
+"There is a convention of sending the multi-byte data over IP _MSB first_. "
+"This, we will refer to as the _network byte order_, or simply the _network "
+"order_."
+msgstr ""
+"Существует соглашение о передаче многобайтовых данных по IP _старшим байтом "
+"вперёд_. Это мы будем называть _порядком байтов сети_ или просто _сетевым "
+"порядком_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:470
+msgid ""
+"Now, if we compiled the above code for an Intel based computer, our _host "
+"byte order_ would produce:"
+msgstr ""
+"Вот, если бы мы скомпилировали приведённый выше код для компьютера на базе "
+"Intel, наш _порядок байтов хоста_ выдал бы:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:471
+#, no-wrap
+msgid "Host byte order on an Intel system"
+msgstr "Порядок байтов на хосте в системе Intel"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:475
+msgid "But the _network byte order_ requires that we store the data MSB first:"
+msgstr ""
+"Но порядок байтов в _сетевом формате_ требует, чтобы данные хранились "
+"начиная со старшего байта (MSB):"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:476
+#, no-wrap
+msgid "Network byte order"
+msgstr "Порядок байтов в сети"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:480
+msgid ""
+"Unfortunately, our _host order_ is the exact opposite of the _network order_."
+msgstr ""
+"К сожалению, наш _порядок хоста_ полностью противоположен _порядку сети_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:483
+msgid ""
+"We have several ways of dealing with it. One would be to _reverse_ the "
+"values in our code:"
+msgstr ""
+"У нас есть несколько способов решения этой проблемы. Один из них — "
+"_инвертировать_ значения в нашем коде:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:489
+#, no-wrap
+msgid ""
+"sa.sin_family = AF_INET;\n"
+"sa.sin_port = 13 << 8;\n"
+"sa.sin_addr.s_addr = (((((18 << 8) | 244) << 8) | 43) << 8) | 192;\n"
+msgstr ""
+"sa.sin_family = AF_INET;\n"
+"sa.sin_port = 13 << 8;\n"
+"sa.sin_addr.s_addr = (((((18 << 8) | 244) << 8) | 43) << 8) | 192;\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:494
+msgid ""
+"This will _trick_ our compiler into storing the data in the _network byte "
+"order_. In some cases, this is exactly the way to do it (e.g., when "
+"programming in assembly language). In most cases, however, it can cause a "
+"problem."
+msgstr ""
+"Это _обманет_ наш компилятор, заставив его сохранить данные в _порядке "
+"байтов сети_. В некоторых случаях это именно тот способ, который нужен "
+"(например, при программировании на ассемблере). Однако в большинстве случаев "
+"это может вызвать проблему."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:498
+msgid ""
+"Suppose, you wrote a sockets-based program in C. You know it is going to "
+"run on a Pentium(R), so you enter all your constants in reverse and force "
+"them to the _network byte order_. It works well."
+msgstr ""
+"Предположим, вы написали программу на C, использующую сокеты. Вы знаете, что "
+"она будет работать на Pentium(R), поэтому вводите все константы в обратном "
+"порядке и приводите их к _порядку байтов сети_. Она работает хорошо."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:503
+msgid ""
+"Then, some day, your trusted old Pentium(R) becomes a rusty old Pentium(R). "
+"You replace it with a system whose _host order_ is the same as the _network "
+"order_. You need to recompile all your software. All of your software "
+"continues to perform well, except the one program you wrote."
+msgstr ""
+"Затем, однажды, ваш надежный старый Pentium(R) превращается в ржавый старый "
+"Pentium(R). Вы заменяете его системой, у которой _порядок байтов хоста_ "
+"совпадает с _сетевым порядком байтов_. Вам нужно перекомпилировать все ваше "
+"программное обеспечение. Все ваши программы продолжают работать хорошо, "
+"кроме той одной программы, которую вы написали."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:507
+msgid ""
+"You have since forgotten that you had forced all of your constants to the "
+"opposite of the _host order_. You spend some quality time tearing out your "
+"hair, calling the names of all gods you ever heard of (and some you made "
+"up), hitting your monitor with a nerf bat, and performing all the other "
+"traditional ceremonies of trying to figure out why something that has worked "
+"so well is suddenly not working at all."
+msgstr ""
+"Вы уже забыли, что принудительно задали все свои константы противоположными "
+"_порядку хоста_. Вы проводите некоторое время, яростно рвя на себе волосы, "
+"взывая ко всем известным вам богам (и к некоторым, которых вы придумали), "
+"стуча нерф-битой по монитору и выполняя прочие традиционные ритуалы в "
+"попытке понять, почему то, что работало так хорошо, внезапно перестало "
+"работать вообще."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:509
+msgid ""
+"Eventually, you figure it out, say a couple of swear words, and start "
+"rewriting your code."
+msgstr ""
+"В конце концов, вы разбираетесь в проблеме, произносите пару крепких "
+"словечек и начинаете переписывать свой код."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:512
+msgid ""
+"Luckily, you are not the first one to face the problem. Someone else has "
+"created the man:htons[3] and man:htonl[3] C functions to convert a `short` "
+"and `long` respectively from the _host byte order_ to the _network byte "
+"order_, and the man:ntohs[3] and man:ntohl[3] C functions to go the other "
+"way."
+msgstr ""
+"К счастью, вы не первый, кто столкнулся с этой проблемой. Кто-то уже создал "
+"функции man:htons[3] и man:htonl[3] на языке C для преобразования `short` и "
+"`long` соответственно из _порядка байтов хоста_ в _порядок байтов сети_, а "
+"также функции man:ntohs[3] и man:ntohl[3] на языке C для обратного "
+"преобразования."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:515
+msgid ""
+"On _MSB-first_ systems these functions do nothing. On _LSB-first_ systems "
+"they convert values to the proper order."
+msgstr ""
+"На системах с порядком _старший байт первый_ эти функции не выполняют "
+"никаких действий. На системах с порядком _младший байт первый_ они "
+"преобразуют значения в правильный порядок."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:517
+msgid ""
+"So, regardless of what system your software is compiled on, your data will "
+"end up in the correct order if you use these functions."
+msgstr ""
+"Итак, независимо от того, на какой системе компилируется ваше программное "
+"обеспечение, ваши данные будут в правильном порядке, если вы используете эти "
+"функции."
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:519
+#, no-wrap
+msgid "Client Functions"
+msgstr "Функции клиента"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:524
+msgid ""
+"Typically, the client initiates the connection to the server. The client "
+"knows which server it is about to call: It knows its IP address, and it "
+"knows the _port_ the server resides at. It is akin to you picking up the "
+"phone and dialing the number (the _address_), then, after someone answers, "
+"asking for the person in charge of wingdings (the _port_)."
+msgstr ""
+"Обычно клиент инициирует подключение к серверу. Клиент знает, к какому "
+"серверу он собирается обратиться: он знает его IP-адрес и _порт_, на котором "
+"работает сервер. Это похоже на то, как вы поднимаете трубку и набираете "
+"номер (_адрес_), а затем, когда кто-то отвечает, просите соединить со "
+"специалистом по непонятным символам (_порт_)."
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:526
+#, no-wrap
+msgid "`connect`"
+msgstr "`connect`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:529
+msgid ""
+"Once a client has created a socket, it needs to connect it to a specific "
+"port on a remote system. It uses man:connect[2]:"
+msgstr ""
+"Как только клиент создал сокет, ему нужно подключить его к определённому "
+"порту на удалённой системе. Для этого используется man:connect[2]:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:533
+#, no-wrap
+msgid "int connect(int s, const struct sockaddr *name, socklen_t namelen);\n"
+msgstr "int connect(int s, const struct sockaddr *name, socklen_t namelen);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:538
+msgid ""
+"The `s` argument is the socket, i.e., the value returned by the `socket` "
+"function. The `name` is a pointer to `sockaddr`, the structure we have "
+"talked about extensively. Finally, `namelen` informs the system how many "
+"bytes are in our `sockaddr` structure."
+msgstr ""
+"Аргумент `s` — это сокет, то есть значение, возвращаемое функцией `socket`. "
+"Аргумент `name` — это указатель на структуру `sockaddr`, которую мы подробно "
+"обсуждали. Наконец, `namelen` сообщает системе, сколько байт находится в "
+"нашей структуре `sockaddr`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:541
+msgid ""
+"If `connect` is successful, it returns `0`. Otherwise it returns `-1` and "
+"stores the error code in `errno`."
+msgstr ""
+"Если `connect` завершается успешно, он возвращает `0`. В противном случае "
+"возвращается `-1`, а код ошибки сохраняется в `errno`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:545
+msgid ""
+"There are many reasons why `connect` may fail. For example, with an attempt "
+"to an Internet connection, the IP address may not exist, or it may be down, "
+"or just too busy, or it may not have a server listening at the specified "
+"port. Or it may outright _refuse_ any request for specific code."
+msgstr ""
+"Существует множество причин, по которым `connect` может завершиться "
+"неудачей. Например, при попытке подключения к интернету, IP-адрес может не "
+"существовать, быть недоступен, перегружен или на указанном порту может не "
+"быть сервера. Или же подключение может быть явно _отклонено_ по определённым "
+"причинам."
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:547
+#, no-wrap
+msgid "Our First Client"
+msgstr "Наш первый клиент"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:550
+msgid ""
+"We now know enough to write a very simple client, one that will get current "
+"time from `192.43.244.18` and print it to [.filename]#stdout#."
+msgstr ""
+"Теперь мы знаем достаточно, чтобы написать очень простого клиента, который "
+"получит текущее время от `192.43.244.18` и выведет его в [.filename]#stdout#."
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:564
+#, no-wrap
+msgid ""
+"/*\n"
+" * daytime.c\n"
+" *\n"
+" * Programmed by G. Adam Stanislav\n"
+" */\n"
+"#include <stdio.h>\n"
+"#include <string.h>\n"
+"#include <sys/types.h>\n"
+"#include <sys/socket.h>\n"
+"#include <netinet/in.h>\n"
+"#include <unistd.h>\n"
+msgstr ""
+"/*\n"
+" * daytime.c\n"
+" *\n"
+" * Programmed by G. Adam Stanislav\n"
+" */\n"
+"#include <stdio.h>\n"
+"#include <string.h>\n"
+"#include <sys/types.h>\n"
+"#include <sys/socket.h>\n"
+"#include <netinet/in.h>\n"
+"#include <unistd.h>\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:569
+#, no-wrap
+msgid ""
+"int main() {\n"
+" int s, bytes;\n"
+" struct sockaddr_in sa;\n"
+" char buffer[BUFSIZ+1];\n"
+msgstr ""
+"int main() {\n"
+" int s, bytes;\n"
+" struct sockaddr_in sa;\n"
+" char buffer[BUFSIZ+1];\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:574
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:993
+#, no-wrap
+msgid ""
+" if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {\n"
+" perror(\"socket\");\n"
+" return 1;\n"
+" }\n"
+msgstr ""
+" if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {\n"
+" perror(\"socket\");\n"
+" return 1;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:576
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:995
+#, no-wrap
+msgid " memset(&sa, '\\0', sizeof(sa));\n"
+msgstr " memset(&sa, '\\0', sizeof(sa));\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:585
+#, no-wrap
+msgid ""
+" sa.sin_family = AF_INET;\n"
+" sa.sin_port = htons(13);\n"
+" sa.sin_addr.s_addr = htonl((((((192 << 8) | 43) << 8) | 244) << 8) | 18);\n"
+" if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {\n"
+" perror(\"connect\");\n"
+" close(s);\n"
+" return 2;\n"
+" }\n"
+msgstr ""
+" sa.sin_family = AF_INET;\n"
+" sa.sin_port = htons(13);\n"
+" sa.sin_addr.s_addr = htonl((((((192 << 8) | 43) << 8) | 244) << 8) | 18);\n"
+" if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {\n"
+" perror(\"connect\");\n"
+" close(s);\n"
+" return 2;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:588
+#, no-wrap
+msgid ""
+" while ((bytes = read(s, buffer, BUFSIZ)) > 0)\n"
+" write(1, buffer, bytes);\n"
+msgstr ""
+" while ((bytes = read(s, buffer, BUFSIZ)) > 0)\n"
+" write(1, buffer, bytes);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:592
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1019
+#, no-wrap
+msgid ""
+" close(s);\n"
+" return 0;\n"
+"}\n"
+msgstr ""
+" close(s);\n"
+" return 0;\n"
+"}\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:595
+msgid ""
+"Go ahead, enter it in your editor, save it as [.filename]#daytime.c#, then "
+"compile and run it:"
+msgstr ""
+"Вперед! Введите это в вашем редакторе, сохраните как [.filename]#daytime.c#, "
+"затем скомпилируйте и запустите:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:600
+#, no-wrap
+msgid ""
+"% cc -O3 -o daytime daytime.c\n"
+"% ./daytime\n"
+msgstr ""
+"% cc -O3 -o daytime daytime.c\n"
+"% ./daytime\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:603
+#, no-wrap
+msgid ""
+"52079 01-06-19 02:29:25 50 0 1 543.9 UTC(NIST) *\n"
+"%\n"
+msgstr ""
+"52079 01-06-19 02:29:25 50 0 1 543.9 UTC(NIST) *\n"
+"%\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:607
+msgid ""
+"In this case, the date was June 19, 2001, the time was 02:29:25 UTC. "
+"Naturally, your results will vary."
+msgstr ""
+"В данном случае дата была 19 июня 2001 года, время — 02:29:25 UTC. "
+"Естественно, ваши результаты могут отличаться."
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:609
+#, no-wrap
+msgid "Server Functions"
+msgstr "Функции сервера"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:615
+msgid ""
+"The typical server does not initiate the connection. Instead, it waits for "
+"a client to call it and request services. It does not know when the client "
+"will call, nor how many clients will call. It may be just sitting there, "
+"waiting patiently, one moment, The next moment, it can find itself swamped "
+"with requests from a number of clients, all calling in at the same time."
+msgstr ""
+"Типичный сервер не инициирует соединение. Вместо этого он ожидает, когда "
+"клиент обратится к нему и запросит услуги. Он не знает, когда клиент "
+"обратится, ни сколько клиентов обратится. В один момент он может просто "
+"спокойно ожидать, а в следующий момент он может оказаться перегруженным "
+"запросами от множества клиентов, обращающихся одновременно."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:617
+msgid "The sockets interface offers three basic functions to handle this."
+msgstr ""
+"Интерфейс сокетов предоставляет три основные функции для обработки этого."
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:619
+#, no-wrap
+msgid "`bind`"
+msgstr "`bind`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:622
+msgid ""
+"Ports are like extensions to a phone line: After you dial a number, you dial "
+"the extension to get to a specific person or department."
+msgstr ""
+"Порты подобны внутренним номерам телефонной линии: после набора основного "
+"номера вы набираете внутренний номер, чтобы связаться с конкретным человеком "
+"или отделом."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:626
+msgid ""
+"There are 65535 IP ports, but a server usually processes requests that come "
+"in on only one of them. It is like telling the phone room operator that we "
+"are now at work and available to answer the phone at a specific extension. "
+"We use man:bind[2] to tell sockets which port we want to serve."
+msgstr ""
+"Существует 65535 IP-портов, но сервер обычно обрабатывает запросы, "
+"поступающие только на один из них. Это как сказать оператору телефонной "
+"комнаты, что мы сейчас на месте и готовы отвечать на звонки по определённому "
+"внутреннему номеру. Мы используем man:bind[2], чтобы указать сокетам, на "
+"каком порту мы хотим обслуживать запросы."
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:630
+#, no-wrap
+msgid "int bind(int s, const struct sockaddr *addr, socklen_t addrlen);\n"
+msgstr "int bind(int s, const struct sockaddr *addr, socklen_t addrlen);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:635
+msgid ""
+"Beside specifying the port in `addr`, the server may include its IP "
+"address. However, it can just use the symbolic constant INADDR_ANY to "
+"indicate it will serve all requests to the specified port regardless of what "
+"its IP address is. This symbol, along with several similar ones, is "
+"declared in [.filename]#netinet/in.h#"
+msgstr ""
+"Помимо указания порта в `addr`, сервер может включать свой IP-адрес. Однако "
+"он может просто использовать символическую константу INADDR_ANY, чтобы "
+"указать, что будет обслуживать все запросы на указанный порт, независимо от "
+"его IP-адреса. Этот символ, наряду с несколькими аналогичными, объявлен в "
+"[.filename]#netinet/in.h#"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:639
+#, no-wrap
+msgid "#define\tINADDR_ANY\t\t(u_int32_t)0x00000000\n"
+msgstr "#define\tINADDR_ANY\t\t(u_int32_t)0x00000000\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:644
+msgid ""
+"Suppose we were writing a server for the _daytime_ protocol over TCP/IP. "
+"Recall that it uses port 13. Our `sockaddr_in` structure would look like "
+"this:"
+msgstr ""
+"Предположим, мы пишем сервер для протокола _daytime_ поверх TCP/IP. "
+"Напомним, что он использует порт 13. Наша структура `sockaddr_in` будет "
+"выглядеть так:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:645
+#, no-wrap
+msgid "Example Server sockaddr_in"
+msgstr "Пример sockaddr_in сервера"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:646
+#, no-wrap
+msgid "sainserv.png"
+msgstr "sainserv.png"
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:649
+#, no-wrap
+msgid "`listen`"
+msgstr "`listen`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:653
+msgid ""
+"To continue our office phone analogy, after you have told the phone central "
+"operator what extension you will be at, you now walk into your office, and "
+"make sure your own phone is plugged in and the ringer is turned on. Plus, "
+"you make sure your call waiting is activated, so you can hear the phone ring "
+"even while you are talking to someone."
+msgstr ""
+"Продолжая аналогию с офисным телефоном, после того как вы сообщили оператору "
+"АТС, на каком внутреннем номере вы будете находиться, вы заходите в свой "
+"офис и убеждаетесь, что ваш телефон подключен и звонок включен. Кроме того, "
+"вы активируете функцию ожидания вызова, чтобы слышать звонок даже во время "
+"разговора с кем-то."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:655
+msgid "The server ensures all of that with the man:listen[2] function."
+msgstr "Сервер обеспечивает все это с помощью функции man:listen[2]."
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:659
+#, no-wrap
+msgid "int listen(int s, int backlog);\n"
+msgstr "int listen(int s, int backlog);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:663
+msgid ""
+"In here, the `backlog` variable tells sockets how many incoming requests to "
+"accept while you are busy processing the last request. In other words, it "
+"determines the maximum size of the queue of pending connections."
+msgstr ""
+"Здесь переменная `backlog` указывает сокетам, сколько входящих запросов "
+"принимать, пока вы заняты обработкой последнего запроса. Другими словами, "
+"она определяет максимальный размер очереди ожидающих соединений."
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:665
+#, no-wrap
+msgid "`accept`"
+msgstr "`accept`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:670
+msgid ""
+"After you hear the phone ringing, you accept the call by answering the "
+"call. You have now established a connection with your client. This "
+"connection remains active until either you or your client hang up."
+msgstr ""
+"После того как вы услышите телефонный звонок, вы принимаете вызов, отвечая "
+"на звонок. Теперь вы установили соединение с вашим клиентом. Это соединение "
+"остается активным, пока вы или ваш клиент не повесите трубку."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:672
+msgid "The server accepts the connection by using the man:accept[2] function."
+msgstr "Сервер принимает соединение, используя функцию man:accept[2]."
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:676
+#, no-wrap
+msgid "int accept(int s, struct sockaddr *addr, socklen_t *addrlen);\n"
+msgstr "int accept(int s, struct sockaddr *addr, socklen_t *addrlen);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:680
+msgid ""
+"Note that this time `addrlen` is a pointer. This is necessary because in "
+"this case it is the socket that fills out `addr`, the `sockaddr_in` "
+"structure."
+msgstr ""
+"Обратите внимание, что в этот раз `addrlen` является указателем. Это "
+"необходимо, потому что в данном случае именно сокет заполняет структуру "
+"`addr` — `sockaddr_in`."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:684
+msgid ""
+"The return value is an integer. Indeed, the `accept` returns a _new "
+"socket_. You will use this new socket to communicate with the client."
+msgstr ""
+"Возвращаемое значение является целым числом. Действительно, `accept` "
+"возвращает _новый сокет_. Этот новый сокет будет использоваться для обмена "
+"данными с клиентом."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:686
+msgid ""
+"What happens to the old socket? It continues to listen for more requests "
+"(remember the `backlog` variable we passed to `listen`?) until we `close` it."
+msgstr ""
+"Что происходит со старым сокетом? Он продолжает ожидать новые запросы "
+"(помните переменную `backlog`, которую мы передали в `listen`?), пока мы не "
+"закроем его (`close`)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:690
+msgid ""
+"Now, the new socket is meant only for communications. It is fully "
+"connected. We cannot pass it to `listen` again, trying to accept additional "
+"connections."
+msgstr ""
+"Теперь новый сокет предназначен только для обмена данными. Он полностью "
+"подключен. Мы не можем снова передать его в `listen`, чтобы принимать "
+"дополнительные соединения."
+
+#. type: Title =====
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:692
+#, no-wrap
+msgid "Our First Server"
+msgstr "Наш первый сервер"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:696
+msgid ""
+"Our first server will be somewhat more complex than our first client was: "
+"Not only do we have more sockets functions to use, but we need to write it "
+"as a daemon."
+msgstr ""
+"Наш первый сервер будет несколько сложнее, чем первый клиент: нам нужно не "
+"только использовать больше функций сокетов, но и написать его как демон."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:699
+msgid ""
+"This is best achieved by creating a _child process_ after binding the port. "
+"The main process then exits and returns control to the shell (or whatever "
+"program invoked it)."
+msgstr ""
+"Это лучше всего достигается созданием _дочернего процесса_ после привязки "
+"порта. Затем основной процесс завершается и возвращает управление оболочке "
+"(или любой другой программе, которая его вызвала)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:701
+msgid ""
+"The child calls `listen`, then starts an endless loop, which accepts a "
+"connection, serves it, and eventually closes its socket."
+msgstr ""
+"Дочерний процесс вызывает `listen`, затем запускает бесконечный цикл, "
+"который принимает соединение, обслуживает его и в конечном итоге закрывает "
+"свой сокет."
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:717
+#, no-wrap
+msgid ""
+"/*\n"
+" * daytimed - a port 13 server\n"
+" *\n"
+" * Programmed by G. Adam Stanislav\n"
+" * June 19, 2001\n"
+" */\n"
+"#include <stdio.h>\n"
+"#include <string.h>\n"
+"#include <time.h>\n"
+"#include <unistd.h>\n"
+"#include <sys/types.h>\n"
+"#include <sys/socket.h>\n"
+"#include <netinet/in.h>\n"
+msgstr ""
+"/*\n"
+" * daytimed - a port 13 server\n"
+" *\n"
+" * Programmed by G. Adam Stanislav\n"
+" * June 19, 2001\n"
+" */\n"
+"#include <stdio.h>\n"
+"#include <string.h>\n"
+"#include <time.h>\n"
+"#include <unistd.h>\n"
+"#include <sys/types.h>\n"
+"#include <sys/socket.h>\n"
+"#include <netinet/in.h>\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:719
+#, no-wrap
+msgid "#define BACKLOG 4\n"
+msgstr "#define BACKLOG 4\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:727
+#, no-wrap
+msgid ""
+"int main() {\n"
+" int s, c;\n"
+" socklen_t b;\n"
+" struct sockaddr_in sa;\n"
+" time_t t;\n"
+" struct tm *tm;\n"
+" FILE *client;\n"
+msgstr ""
+"int main() {\n"
+" int s, c;\n"
+" socklen_t b;\n"
+" struct sockaddr_in sa;\n"
+" time_t t;\n"
+" struct tm *tm;\n"
+" FILE *client;\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:732
+#, no-wrap
+msgid ""
+" if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {\n"
+" perror(\"socket\");\n"
+" return 1;\n"
+" }\n"
+msgstr ""
+" if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {\n"
+" perror(\"socket\");\n"
+" return 1;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:734
+#, no-wrap
+msgid " memset(&sa, '\\0', sizeof(sa));\n"
+msgstr " memset(&sa, '\\0', sizeof(sa));\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:737
+#, no-wrap
+msgid ""
+" sa.sin_family = AF_INET;\n"
+" sa.sin_port = htons(13);\n"
+msgstr ""
+" sa.sin_family = AF_INET;\n"
+" sa.sin_port = htons(13);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:740
+#, no-wrap
+msgid ""
+" if (INADDR_ANY)\n"
+" sa.sin_addr.s_addr = htonl(INADDR_ANY);\n"
+msgstr ""
+" if (INADDR_ANY)\n"
+" sa.sin_addr.s_addr = htonl(INADDR_ANY);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:745
+#, no-wrap
+msgid ""
+" if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0) {\n"
+" perror(\"bind\");\n"
+" return 2;\n"
+" }\n"
+msgstr ""
+" if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0) {\n"
+" perror(\"bind\");\n"
+" return 2;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:756
+#, no-wrap
+msgid ""
+" switch (fork()) {\n"
+" case -1:\n"
+" perror(\"fork\");\n"
+" return 3;\n"
+" default:\n"
+" close(s);\n"
+" return 0;\n"
+" case 0:\n"
+" break;\n"
+" }\n"
+msgstr ""
+" switch (fork()) {\n"
+" case -1:\n"
+" perror(\"fork\");\n"
+" return 3;\n"
+" default:\n"
+" close(s);\n"
+" return 0;\n"
+" case 0:\n"
+" break;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:758
+#, no-wrap
+msgid " listen(s, BACKLOG);\n"
+msgstr " listen(s, BACKLOG);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:761
+#, no-wrap
+msgid ""
+" for (;;) {\n"
+" b = sizeof sa;\n"
+msgstr ""
+" for (;;) {\n"
+" b = sizeof sa;\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:766
+#, no-wrap
+msgid ""
+" if ((c = accept(s, (struct sockaddr *)&sa, &b)) < 0) {\n"
+" perror(\"daytimed accept\");\n"
+" return 4;\n"
+" }\n"
+msgstr ""
+" if ((c = accept(s, (struct sockaddr *)&sa, &b)) < 0) {\n"
+" perror(\"daytimed accept\");\n"
+" return 4;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:771
+#, no-wrap
+msgid ""
+" if ((client = fdopen(c, \"w\")) == NULL) {\n"
+" perror(\"daytimed fdopen\");\n"
+" return 5;\n"
+" }\n"
+msgstr ""
+" if ((client = fdopen(c, \"w\")) == NULL) {\n"
+" perror(\"daytimed fdopen\");\n"
+" return 5;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:776
+#, no-wrap
+msgid ""
+" if ((t = time(NULL)) < 0) {\n"
+" perror(\"daytimed time\");\n"
+" return 6;\n"
+" }\n"
+msgstr ""
+" if ((t = time(NULL)) < 0) {\n"
+" perror(\"daytimed time\");\n"
+" return 6;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:785
+#, no-wrap
+msgid ""
+" tm = gmtime(&t);\n"
+" fprintf(client, \"%.4i-%.2i-%.2iT%.2i:%.2i:%.2iZ\\n\",\n"
+" tm->tm_year + 1900,\n"
+" tm->tm_mon + 1,\n"
+" tm->tm_mday,\n"
+" tm->tm_hour,\n"
+" tm->tm_min,\n"
+" tm->tm_sec);\n"
+msgstr ""
+" tm = gmtime(&t);\n"
+" fprintf(client, \"%.4i-%.2i-%.2iT%.2i:%.2i:%.2iZ\\n\",\n"
+" tm->tm_year + 1900,\n"
+" tm->tm_mon + 1,\n"
+" tm->tm_mday,\n"
+" tm->tm_hour,\n"
+" tm->tm_min,\n"
+" tm->tm_sec);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:789
+#, no-wrap
+msgid ""
+" fclose(client);\n"
+" }\n"
+"}\n"
+msgstr ""
+" fclose(client);\n"
+" }\n"
+"}\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:794
+msgid ""
+"We start by creating a socket. Then we fill out the `sockaddr_in` structure "
+"in `sa`. Note the conditional use of INADDR_ANY:"
+msgstr ""
+"Начинаем с создания сокета. Затем заполняем структуру `sockaddr_in` в `sa`. "
+"Обратите внимание на условное использование INADDR_ANY:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:799
+#, no-wrap
+msgid ""
+"if (INADDR_ANY)\n"
+" sa.sin_addr.s_addr = htonl(INADDR_ANY);\n"
+msgstr ""
+"if (INADDR_ANY)\n"
+" sa.sin_addr.s_addr = htonl(INADDR_ANY);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:806
+msgid ""
+"Its value is `0`. Since we have just used `bzero` on the entire structure, "
+"it would be redundant to set it to `0` again. But if we port our code to "
+"some other system where INADDR_ANY is perhaps not a zero, we need to assign "
+"it to `sa.sin_addr.s_addr`. Most modern C compilers are clever enough to "
+"notice that INADDR_ANY is a constant. As long as it is a zero, they will "
+"optimize the entire conditional statement out of the code."
+msgstr ""
+"Его значение равно `0`. Поскольку мы только что использовали `bzero` для "
+"всей структуры, будет избыточным снова устанавливать его в `0`. Но если мы "
+"перенесем наш код на другую систему, где INADDR_ANY, возможно, не равен "
+"нулю, нам нужно будет присвоить его `sa.sin_addr.s_addr`. Большинство "
+"современных компиляторов C достаточно умны, чтобы заметить, что INADDR_ANY — "
+"это константа. Пока она равна нулю, они оптимизируют все условное выражение "
+"из кода."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:810
+msgid ""
+"After we have called `bind` successfully, we are ready to become a _daemon_: "
+"We use `fork` to create a child process. In both, the parent and the child, "
+"the `s` variable is our socket. The parent process will not need it, so it "
+"calls `close`, then it returns `0` to inform its own parent it had "
+"terminated successfully."
+msgstr ""
+"После успешного вызова `bind` мы готовы стать _демоном_: используем `fork` "
+"для создания дочернего процесса. В обоих процессах, родительском и дочернем, "
+"переменная `s` является нашим сокетом. Родительскому процессу он больше не "
+"нужен, поэтому он вызывает `close`, затем возвращает `0`, чтобы сообщить "
+"своему родителю об успешном завершении."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:815
+msgid ""
+"Meanwhile, the child process continues working in the background. It calls "
+"`listen` and sets its backlog to `4`. It does not need a large value here "
+"because _daytime_ is not a protocol many clients request all the time, and "
+"because it can process each request instantly anyway."
+msgstr ""
+"Между тем, дочерний процесс продолжает работать в фоновом режиме. Он "
+"вызывает `listen` и устанавливает размер очереди ожидания (`backlog`) равным "
+"`4`. Здесь не требуется большое значение, так как _daytime_ — это не "
+"протокол, который часто запрашивают клиенты, и, кроме того, он может "
+"мгновенно обрабатывать каждый запрос."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:817
+msgid ""
+"Finally, the daemon starts an endless loop, which performs the following "
+"steps:"
+msgstr ""
+"Наконец, демон запускает бесконечный цикл, который выполняет следующие шаги:"
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:820
+msgid ""
+"Call `accept`. It waits here until a client contacts it. At that point, it "
+"receives a new socket, `c`, which it can use to communicate with this "
+"particular client."
+msgstr ""
+"Вызовите `accept`. Он ожидает здесь, пока клиент не свяжется с ним. В этот "
+"момент он получает новый сокет, `c`, который можно использовать для обмена "
+"данными с этим конкретным клиентом."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:821
+msgid ""
+"It uses the C function `fdopen` to turn the socket from a low-level _file "
+"descriptor_ to a C-style `FILE` pointer. This will allow the use of "
+"`fprintf` later on."
+msgstr ""
+"Он использует функцию C `fdopen` для преобразования сокета из "
+"низкоуровневого _дескриптора файла_ в указатель типа `FILE` в стиле C. Это "
+"позволит в дальнейшем использовать `fprintf`."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:822
+msgid ""
+"It checks the time, and prints it in the _ISO 8601_ format to the `client` "
+"\"file\". It then uses `fclose` to close the file. That will automatically "
+"close the socket as well."
+msgstr ""
+"Он проверяет время и выводит его в формате _ISO 8601_ в «файл» `client`. "
+"Затем он использует `fclose` для закрытия файла. Это также автоматически "
+"закроет сокет."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:824
+msgid "We can _generalize_ this, and use it as a model for many other servers:"
+msgstr ""
+"Мы можем _обобщить_ это и использовать в качестве модели для многих других "
+"серверов:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:825
+#, no-wrap
+msgid "Sequential Server"
+msgstr "Последовательный Сервер"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:826
+#, no-wrap
+msgid "serv.png"
+msgstr "serv.png"
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:832
+msgid ""
+"This flowchart is good for _sequential servers_, i.e., servers that can "
+"serve one client at a time, just as we were able to with our _daytime_ "
+"server. This is only possible whenever there is no real \"conversation\" "
+"going on between the client and the server: As soon as the server detects a "
+"connection to the client, it sends out some data and closes the connection. "
+"The entire operation may take nanoseconds, and it is finished."
+msgstr ""
+"Эта блок-схема подходит для _последовательных серверов_, то есть серверов, "
+"которые могут обслуживать одного клиента за раз, как это было возможно с "
+"нашим _daytime_ сервером. Это возможно только в тех случаях, когда между "
+"клиентом и сервером не происходит реального \"диалога\": как только сервер "
+"обнаруживает подключение клиента, он отправляет некоторые данные и закрывает "
+"соединение. Вся операция может занять наносекунды, и она завершена."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:835
+msgid ""
+"The advantage of this flowchart is that, except for the brief moment after "
+"the parent ``fork``s and before it exits, there is always only one _process_ "
+"active: Our server does not take up much memory and other system resources."
+msgstr ""
+"Преимущество этой блок-схемы в том, что, за исключением короткого момента "
+"после того, как родительский процесс выполняет ``fork`` и до его завершения, "
+"всегда активен только один _процесс_: Наш сервер не занимает много памяти и "
+"других системных ресурсов."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:839
+msgid ""
+"Note that we have added _initialize daemon_ in our flowchart. We did not "
+"need to initialize our own daemon, but this is a good place in the flow of "
+"the program to set up any `signal` handlers, open any files we may need, etc."
+msgstr ""
+"Обратите внимание, что мы добавили _инициализацию демона_ в нашу блок-схему. "
+"Нам не нужно было инициализировать собственный демон, но это подходящее "
+"место в потоке выполнения программы для настройки обработчиков `signal`, "
+"открытия необходимых файлов и т. д."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:843
+msgid ""
+"Just about everything in the flow chart can be used literally on many "
+"different servers. The _serve_ entry is the exception. We think of it as a "
+"_\"black box\"_, i.e., something you design specifically for your own "
+"server, and just \"plug it into the rest.\""
+msgstr ""
+"Почти все элементы блок-схемы могут быть использованы буквально на множестве "
+"различных серверов. Элемент _serve_ является исключением. Мы рассматриваем "
+"его как _\"чёрный ящик\"_, то есть нечто, что вы проектируете специально для "
+"своего сервера и просто \"подключаете к остальной системе.\""
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:849
+msgid ""
+"Not all protocols are that simple. Many receive a request from the client, "
+"reply to it, then receive another request from the same client. As a "
+"result, they do not know in advance how long they will be serving the "
+"client. Such servers usually start a new process for each client. While "
+"the new process is serving its client, the daemon can continue listening for "
+"more connections."
+msgstr ""
+"Не все протоколы настолько просты. Многие получают запрос от клиента, "
+"отвечают на него, а затем получают ещё один запрос от того же клиента. В "
+"результате, они не знают заранее, как долго будут обслуживать клиента. Такие "
+"серверы обычно запускают новый процесс для каждого клиента. Пока новый "
+"процесс обслуживает своего клиента, демон может продолжать прослушивать "
+"новые подключения."
+
+#. type: .procedure
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:852
+msgid ""
+"Now, go ahead, save the above source code as [.filename]#daytimed.c# (it is "
+"customary to end the names of daemons with the letter `d`). After you have "
+"compiled it, try running it:"
+msgstr ""
+"Теперь сохраните приведённый исходный код в файл [.filename]#daytimed.c# "
+"(обычно имена демонов оканчиваются буквой `d`). После компиляции попробуйте "
+"запустить его:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:858
+#, no-wrap
+msgid ""
+"% ./daytimed\n"
+"bind: Permission denied\n"
+"%\n"
+msgstr ""
+"% ./daytimed\n"
+"bind: Permission denied\n"
+"%\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:862
+msgid ""
+"What happened here? As you will recall, the _daytime_ protocol uses port "
+"13. But all ports below 1024 are reserved to the superuser (otherwise, "
+"anyone could start a daemon pretending to serve a commonly used port, while "
+"causing a security breach)."
+msgstr ""
+"Что произошло? Как вы помните, протокол _daytime_ использует порт 13. Однако "
+"все порты ниже 1024 зарезервированы для суперпользователя (в противном "
+"случае любой мог бы запустить демон, притворяясь, что обслуживает часто "
+"используемый порт, создавая угрозу безопасности)."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:864
+msgid "Try again, this time as the superuser:"
+msgstr "Попробуйте снова, на этот раз как суперпользователь:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:869
+#, no-wrap
+msgid ""
+"# ./daytimed\n"
+"#\n"
+msgstr ""
+"# ./daytimed\n"
+"#\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:872
+msgid "What... Nothing? Let us try again:"
+msgstr "Что... Ничего? Давайте попробуем еще раз:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:876
+#, no-wrap
+msgid "# ./daytimed\n"
+msgstr "# ./daytimed\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:879
+#, no-wrap
+msgid ""
+"bind: Address already in use\n"
+"#\n"
+msgstr ""
+"bind: Address already in use\n"
+"#\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:884
+msgid ""
+"Every port can only be bound by one program at a time. Our first attempt "
+"was indeed successful: It started the child daemon and returned quietly. It "
+"is still running and will continue to run until you either kill it, or any "
+"of its system calls fail, or you reboot the system."
+msgstr ""
+"Каждый порт может быть связан только одной программой одновременно. Наша "
+"первая попытка действительно была успешной: она запустила дочерний демон и "
+"завершилась без ошибок. Он продолжает работать и будет работать до тех пор, "
+"пока вы его не завершите командой kill, пока какой-либо из его системных "
+"вызовов не завершится с ошибкой или пока вы не перезагрузите систему."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:887
+msgid ""
+"Fine, we know it is running in the background. But is it working? How do we "
+"know it is a proper _daytime_ server? Simple:"
+msgstr ""
+"Хорошо, мы знаем, что он работает в фоновом режиме. Но работает ли он? Как "
+"мы можем убедиться, что это настоящий сервер _daytime_? Просто:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:891
+#, no-wrap
+msgid "% telnet localhost 13\n"
+msgstr "% telnet localhost 13\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:900
+#, no-wrap
+msgid ""
+"Trying ::1...\n"
+"telnet: connect to address ::1: Connection refused\n"
+"Trying 127.0.0.1...\n"
+"Connected to localhost.\n"
+"Escape character is '^]'.\n"
+"2001-06-19T21:04:42Z\n"
+"Connection closed by foreign host.\n"
+"%\n"
+msgstr ""
+"Trying ::1...\n"
+"telnet: connect to address ::1: Connection refused\n"
+"Trying 127.0.0.1...\n"
+"Connected to localhost.\n"
+"Escape character is '^]'.\n"
+"2001-06-19T21:04:42Z\n"
+"Connection closed by foreign host.\n"
+"%\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:905
+msgid ""
+"telnet tried the new IPv6, and failed. It retried with IPv4 and succeeded. "
+"The daemon works."
+msgstr ""
+"telnet попробовал использовать новый IPv6, но не смог. Затем он повторил "
+"попытку с IPv4, и это удалось. Демон работает."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:908
+msgid ""
+"If you have access to another UNIX(R) system via telnet, you can use it to "
+"test accessing the server remotely. My computer does not have a static IP "
+"address, so this is what I did:"
+msgstr ""
+"Если у вас есть доступ к другой UNIX(R)-системе через telnet, вы можете "
+"использовать её для проверки удалённого доступа к серверу. Мой компьютер не "
+"имеет статического IP-адреса, поэтому я сделал следующее:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:912
+#, no-wrap
+msgid "% who\n"
+msgstr "% who\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:916
+#, no-wrap
+msgid ""
+"whizkid ttyp0 Jun 19 16:59 (216.127.220.143)\n"
+"xxx ttyp1 Jun 19 16:06 (xx.xx.xx.xx)\n"
+"% telnet 216.127.220.143 13\n"
+msgstr ""
+"whizkid ttyp0 Jun 19 16:59 (216.127.220.143)\n"
+"xxx ttyp1 Jun 19 16:06 (xx.xx.xx.xx)\n"
+"% telnet 216.127.220.143 13\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:923
+#, no-wrap
+msgid ""
+"Trying 216.127.220.143...\n"
+"Connected to r47.bfm.org.\n"
+"Escape character is '^]'.\n"
+"2001-06-19T21:31:11Z\n"
+"Connection closed by foreign host.\n"
+"%\n"
+msgstr ""
+"Trying 216.127.220.143...\n"
+"Connected to r47.bfm.org.\n"
+"Escape character is '^]'.\n"
+"2001-06-19T21:31:11Z\n"
+"Connection closed by foreign host.\n"
+"%\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:926
+msgid "Again, it worked. Will it work using the domain name?"
+msgstr ""
+"Снова, это сработало. Сработает ли это с использованием доменного имени?"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:930
+#, no-wrap
+msgid "% telnet r47.bfm.org 13\n"
+msgstr "% telnet r47.bfm.org 13\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:937
+#, no-wrap
+msgid ""
+"Trying 216.127.220.143...\n"
+"Connected to r47.bfm.org.\n"
+"Escape character is '^]'.\n"
+"2001-06-19T21:31:40Z\n"
+"Connection closed by foreign host.\n"
+"%\n"
+msgstr ""
+"Trying 216.127.220.143...\n"
+"Connected to r47.bfm.org.\n"
+"Escape character is '^]'.\n"
+"2001-06-19T21:31:40Z\n"
+"Connection closed by foreign host.\n"
+"%\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:941
+msgid ""
+"By the way, telnet prints the _Connection closed by foreign host_ message "
+"after our daemon has closed the socket. This shows us that, indeed, using "
+"`fclose(client);` in our code works as advertised."
+msgstr ""
+"Кстати, telnet выводит сообщение _Connection closed by foreign host_ после "
+"того, как наш демон закрыл сокет. Это показывает, что использование "
+"`fclose(client);` в нашем коде действительно работает, как заявлено."
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:943
+#, no-wrap
+msgid "Helper Functions"
+msgstr "Вспомогательные функции"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:949
+msgid ""
+"FreeBSD C library contains many helper functions for sockets programming. "
+"For example, in our sample client we hard coded the `time.nist.gov` IP "
+"address. But we do not always know the IP address. Even if we do, our "
+"software is more flexible if it allows the user to enter the IP address, or "
+"even the domain name."
+msgstr ""
+"Библиотека C в FreeBSD содержит множество вспомогательных функций для "
+"программирования сокетов. Например, в нашем примере клиента мы жестко "
+"прописали IP-адрес `time.nist.gov`. Но мы не всегда знаем IP-адрес. Даже "
+"если знаем, наше программное обеспечение будет более гибким, если позволит "
+"пользователю ввести IP-адрес или даже доменное имя."
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:951
+#, no-wrap
+msgid "`gethostbyname`"
+msgstr "`gethostbyname`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:954
+msgid ""
+"While there is no way to pass the domain name directly to any of the sockets "
+"functions, the FreeBSD C library comes with the man:gethostbyname[3] and "
+"man:gethostbyname2[3] functions, declared in [.filename]#netdb.h#."
+msgstr ""
+"Хотя нет возможности передать имя домена напрямую в какие-либо функции "
+"сокетов, стандартная библиотека C в FreeBSD предоставляет функции "
+"man:gethostbyname[3] и man:gethostbyname2[3], объявленные в "
+"[.filename]#netdb.h#."
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:959
+#, no-wrap
+msgid ""
+"struct hostent * gethostbyname(const char *name);\n"
+"struct hostent * gethostbyname2(const char *name, int af);\n"
+msgstr ""
+"struct hostent * gethostbyname(const char *name);\n"
+"struct hostent * gethostbyname2(const char *name, int af);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:963
+msgid ""
+"Both return a pointer to the `hostent` structure, with much information "
+"about the domain. For our purposes, the `h_addr_list[0]` field of the "
+"structure points at `h_length` bytes of the correct address, already stored "
+"in the _network byte order_."
+msgstr ""
+"Оба возвращают указатель на структуру `hostent`, содержащую много информации "
+"о домене. Для наших целей поле `h_addr_list[0]` структуры указывает на "
+"`h_length` байтов правильного адреса, уже сохранённого в _порядке байтов "
+"сети_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:965
+msgid ""
+"This allows us to create a much more flexible-and much more useful-version "
+"of our daytime program:"
+msgstr ""
+"Это позволяет нам создать гораздо более гибкую — и гораздо более полезную — "
+"версию нашей программы daytime:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:981
+#, no-wrap
+msgid ""
+"/*\n"
+" * daytime.c\n"
+" *\n"
+" * Programmed by G. Adam Stanislav\n"
+" * 19 June 2001\n"
+" */\n"
+"#include <stdio.h>\n"
+"#include <string.h>\n"
+"#include <unistd.h>\n"
+"#include <sys/types.h>\n"
+"#include <sys/socket.h>\n"
+"#include <netinet/in.h>\n"
+"#include <netdb.h>\n"
+msgstr ""
+"/*\n"
+" * daytime.c\n"
+" *\n"
+" * Programmed by G. Adam Stanislav\n"
+" * 19 June 2001\n"
+" */\n"
+"#include <stdio.h>\n"
+"#include <string.h>\n"
+"#include <unistd.h>\n"
+"#include <sys/types.h>\n"
+"#include <sys/socket.h>\n"
+"#include <netinet/in.h>\n"
+"#include <netdb.h>\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:988
+#, no-wrap
+msgid ""
+"int main(int argc, char *argv[]) {\n"
+" int s, bytes;\n"
+" struct sockaddr_in sa;\n"
+" struct hostent *he;\n"
+" char buf[BUFSIZ+1];\n"
+" char *host;\n"
+msgstr ""
+"int main(int argc, char *argv[]) {\n"
+" int s, bytes;\n"
+" struct sockaddr_in sa;\n"
+" struct hostent *he;\n"
+" char buf[BUFSIZ+1];\n"
+" char *host;\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:998
+#, no-wrap
+msgid ""
+" sa.sin_family = AF_INET;\n"
+" sa.sin_port = htons(13);\n"
+msgstr ""
+" sa.sin_family = AF_INET;\n"
+" sa.sin_port = htons(13);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1000
+#, no-wrap
+msgid " host = (argc > 1) ? argv[1] : \"time.nist.gov\";\n"
+msgstr " host = (argc > 1) ? argv[1] : \"time.nist.gov\";\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1005
+#, no-wrap
+msgid ""
+" if ((he = gethostbyname(host)) == NULL) {\n"
+" herror(host);\n"
+" return 2;\n"
+" }\n"
+msgstr ""
+" if ((he = gethostbyname(host)) == NULL) {\n"
+" herror(host);\n"
+" return 2;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1007
+#, no-wrap
+msgid " memcpy(&sa.sin_addr, he->h_addr_list[0], he->h_length);\n"
+msgstr " memcpy(&sa.sin_addr, he->h_addr_list[0], he->h_length);\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1012
+#, no-wrap
+msgid ""
+" if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {\n"
+" perror(\"connect\");\n"
+" return 3;\n"
+" }\n"
+msgstr ""
+" if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {\n"
+" perror(\"connect\");\n"
+" return 3;\n"
+" }\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1015
+#, no-wrap
+msgid ""
+" while ((bytes = read(s, buf, BUFSIZ)) > 0)\n"
+" write(1, buf, bytes);\n"
+msgstr ""
+" while ((bytes = read(s, buf, BUFSIZ)) > 0)\n"
+" write(1, buf, bytes);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1025
+msgid ""
+"We now can type a domain name (or an IP address, it works both ways) on the "
+"command line, and the program will try to connect to its _daytime_ server. "
+"Otherwise, it will still default to `time.nist.gov`. However, even in this "
+"case we will use `gethostbyname` rather than hard coding `192.43.244.18`. "
+"That way, even if its IP address changes in the future, we will still find "
+"it."
+msgstr ""
+"Теперь мы можем ввести доменное имя (или IP-адрес, это работает в обоих "
+"направлениях) в командной строке, и программа попытается подключиться к его "
+"серверу _daytime_. В противном случае, по умолчанию будет использоваться "
+"`time.nist.gov`. Однако даже в этом случае мы будем использовать "
+"`gethostbyname` вместо жесткого задания `192.43.244.18`. Таким образом, даже "
+"если его IP-адрес изменится в будущем, мы всё равно сможем его найти."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1029
+msgid ""
+"Since it takes virtually no time to get the time from your local server, you "
+"could run daytime twice in a row: First to get the time from "
+"`time.nist.gov`, the second time from your own system. You can then compare "
+"the results and see how exact your system clock is:"
+msgstr ""
+"Поскольку получение времени от локального сервера занимает практически "
+"нулевое время, вы можете запустить daytime дважды подряд: сначала для "
+"получения времени от `time.nist.gov`, а затем от вашей собственной системы. "
+"После этого вы можете сравнить результаты и увидеть, насколько точны часы "
+"вашей системы:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1033
+#, no-wrap
+msgid "% daytime ; daytime localhost\n"
+msgstr "% daytime ; daytime localhost\n"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1037
+#, no-wrap
+msgid ""
+"52080 01-06-20 04:02:33 50 0 0 390.2 UTC(NIST) *\n"
+"2001-06-20T04:02:35Z\n"
+"%\n"
+msgstr ""
+"52080 01-06-20 04:02:33 50 0 0 390.2 UTC(NIST) *\n"
+"2001-06-20T04:02:35Z\n"
+"%\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1040
+msgid "As you can see, my system was two seconds ahead of the NIST time."
+msgstr "Как видно, моя система опережала время NIST на две секунды."
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1042
+#, no-wrap
+msgid "`getservbyname`"
+msgstr "`getservbyname`"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1046
+msgid ""
+"Sometimes you may not be sure what port a certain service uses. The "
+"man:getservbyname[3] function, also declared in [.filename]#netdb.h# comes "
+"in very handy in those cases:"
+msgstr ""
+"Иногда вы можете быть не уверены, какой порт использует определённая служба. "
+"В таких случаях очень полезна функция man:getservbyname[3], также "
+"объявленная в [.filename]#netdb.h#:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1050
+#, no-wrap
+msgid "struct servent * getservbyname(const char *name, const char *proto);\n"
+msgstr "struct servent * getservbyname(const char *name, const char *proto);\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1053
+msgid ""
+"The `servent` structure contains the `s_port`, which contains the proper "
+"port, already in _network byte order_."
+msgstr ""
+"Структура `servent` содержит `s_port`, в котором находится соответствующий "
+"порт, уже в _порядке байтов сети_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1055
+msgid ""
+"Had we not known the correct port for the _daytime_ service, we could have "
+"found it this way:"
+msgstr ""
+"Если бы мы не знали правильный порт для службы _daytime_, мы могли бы найти "
+"его следующим образом:"
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1065
+#, no-wrap
+msgid ""
+"struct servent *se;\n"
+" ...\n"
+" if ((se = getservbyname(\"daytime\", \"tcp\")) == NULL {\n"
+" fprintf(stderr, \"Cannot determine which port to use.\\n\");\n"
+" return 7;\n"
+" }\n"
+" sa.sin_port = se->s_port;\n"
+msgstr ""
+"struct servent *se;\n"
+" ...\n"
+" if ((se = getservbyname(\"daytime\", \"tcp\")) == NULL {\n"
+" fprintf(stderr, \"Cannot determine which port to use.\\n\");\n"
+" return 7;\n"
+" }\n"
+" sa.sin_port = se->s_port;\n"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1072
+msgid ""
+"You usually do know the port. But if you are developing a new protocol, you "
+"may be testing it on an unofficial port. Some day, you will register the "
+"protocol and its port (if nowhere else, at least in your [.filename]#/etc/"
+"services#, which is where `getservbyname` looks). Instead of returning an "
+"error in the above code, you just use the temporary port number. Once you "
+"have listed the protocol in [.filename]#/etc/services#, your software will "
+"find its port without you having to rewrite the code."
+msgstr ""
+"Обычно порт известен. Но если вы разрабатываете новый протокол, вы можете "
+"тестировать его на неофициальном порту. Когда-нибудь вы зарегистрируете "
+"протокол и его порт (если не где-то ещё, то хотя бы в вашем [.filename]#/etc/"
+"services#, где `getservbyname` ищет). Вместо возврата ошибки в приведённом "
+"выше коде вы просто используете временный номер порта. Как только вы "
+"добавите протокол в [.filename]#/etc/services#, ваше программное обеспечение "
+"найдёт его порт без необходимости переписывать код."
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1074
+#, no-wrap
+msgid "Concurrent Servers"
+msgstr "Многозадачные серверы"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1078
+msgid ""
+"Unlike a sequential server, a _concurrent server_ has to be able to serve "
+"more than one client at a time. For example, a _chat server_ may be serving "
+"a specific client for hours-it cannot wait till it stops serving a client "
+"before it serves the next one."
+msgstr ""
+"В отличие от последовательного сервера, _многозадачный сервер_ должен иметь "
+"возможность обслуживать более одного клиента одновременно. Например, _сервер "
+"чата_ может обслуживать конкретного клиента часами — он не может ждать, пока "
+"закончит обслуживать текущего клиента, прежде чем перейти к следующему."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1080
+msgid "This requires a significant change in our flowchart:"
+msgstr "Это требует значительных изменений в нашей блок-схеме:"
+
+#. type: Block title
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1081
+#, no-wrap
+msgid "Concurrent Server"
+msgstr "Многозадачный сервер"
+
+#. type: Target for macro image
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1082
+#, no-wrap
+msgid "serv2.png"
+msgstr "serv2.png"
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1086
+msgid ""
+"We moved the _serve_ from the _daemon process_ to its own _server process_. "
+"However, because each child process inherits all open files (and a socket is "
+"treated just like a file), the new process inherits not only the _\"accepted "
+"handle,\"_ i.e., the socket returned by the `accept` call, but also the _top "
+"socket_, i.e., the one opened by the top process right at the beginning."
+msgstr ""
+"Мы переместили _службу_ из _демона_ в её собственный _серверный процесс_. "
+"Однако, поскольку каждый дочерний процесс наследует все открытые файлы (а "
+"сокет обрабатывается так же, как файл), новый процесс наследует не только "
+"_\"принятый дескриптор\"_, т.е. сокет, возвращённый вызовом `accept`, но и "
+"_главный сокет_, т.е. тот, который был открыт главным процессом в самом "
+"начале."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1089
+msgid ""
+"However, the _server process_ does not need this socket and should `close` "
+"it immediately. Similarly, the _daemon process_ no longer needs the "
+"_accepted socket_, and not only should, but _must_ `close` it-otherwise, it "
+"will run out of available _file descriptors_ sooner or later."
+msgstr ""
+"Однако _серверному процессу_ этот сокет не нужен, и он должен немедленно "
+"вызвать ему `close`. Аналогично, _демону_ больше не нужен _сокет, принятый "
+"вызовом accept_, и он не только должен, но и _обязан_ вызвать ему `close` — "
+"в противном случае рано или поздно закончатся доступные _файловые "
+"дескрипторы_."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1092
+msgid ""
+"After the _server process_ is done serving, it should close the _accepted "
+"socket_. Instead of returning to `accept`, it now exits."
+msgstr ""
+"После завершения обслуживания _серверного процесса_ он должен закрыть "
+"_принятый сокет_. Вместо возврата к `accept`, процесс теперь завершается."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1099
+msgid ""
+"Under UNIX(R), a process does not really _exit_. Instead, it _returns_ to "
+"its parent. Typically, a parent process ``wait``s for its child process, "
+"and obtains a return value. However, our _daemon process_ cannot simply "
+"stop and wait. That would defeat the whole purpose of creating additional "
+"processes. But if it never does `wait`, its children will become _zombies_-"
+"no longer functional but still roaming around."
+msgstr ""
+"В UNIX(R) процесс на самом деле не _завершается_. Вместо этого он "
+"_возвращается_ к своему родителю. Обычно родительский процесс ``ждёт`` "
+"(wait) завершения своего дочернего процесса и получает возвращаемое "
+"значение. Однако наш _демон-процесс_ не может просто остановиться и ждать. "
+"Это бы свело на нет всю цель создания дополнительных процессов. Но если он "
+"никогда не выполняет `wait`, его дочерние процессы станут _зомби_ — более не "
+"функционирующими, но всё ещё бродящими вокруг."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1102
+msgid ""
+"For that reason, the _daemon process_ needs to set _signal handlers_ in its "
+"_initialize daemon_ phase. At least a SIGCHLD signal has to be processed, "
+"so the daemon can remove the zombie return values from the system and "
+"release the system resources they are taking up."
+msgstr ""
+"По этой причине _демону_ необходимо установить _обработчики сигналов_ на "
+"этапе _инициализации демона_. Как минимум, должен обрабатываться сигнал "
+"SIGCHLD, чтобы демон мог удалять зомби-процессы из системы и освобождать "
+"занимаемые ими системные ресурсы."
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/sockets/_index.adoc:1105
+msgid ""
+"That is why our flowchart now contains a _process signals_ box, which is not "
+"connected to any other box. By the way, many servers also process SIGHUP, "
+"and typically interpret as the signal from the superuser that they should "
+"reread their configuration files. This allows us to change settings without "
+"having to kill and restart these servers."
+msgstr ""
+"Вот почему наша блок-схема теперь содержит блок _обработки сигналов_, "
+"который не соединен с другими блоками. Кстати, многие серверы также "
+"обрабатывают SIGHUP и обычно интерпретируют его как сигнал от "
+"суперпользователя, указывающий на необходимость перечитать конфигурационные "
+"файлы. Это позволяет нам изменять настройки без необходимости завершать и "
+"перезапускать эти серверы."