diff options
Diffstat (limited to 'documentation/content/ru/books/developers-handbook/sockets')
-rw-r--r-- | documentation/content/ru/books/developers-handbook/sockets/_index.adoc | 909 | ||||
-rw-r--r-- | documentation/content/ru/books/developers-handbook/sockets/_index.po | 3021 |
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 и обычно интерпретируют его как сигнал от " +"суперпользователя, указывающий на необходимость перечитать конфигурационные " +"файлы. Это позволяет нам изменять настройки без необходимости завершать и " +"перезапускать эти серверы." |