Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

#include <sys/socket.h>

#include <netinet/in.h>

struct sockaddr_in {

 short int sin_family; /* AF_INET */

 unsigned short int sin_port; /* номер порта */

 struct in_addr sin_addr; /* IP-адрес */

}

Первым членом должен быть

AF_INET
, указывающий, что это IP-адрес. Следующий член — это номер порта в сетевом порядке байтов. Последний элемент — это IP-номер машины для данного TCP адреса. IP-номер, хранящийся в
sin_addr
, должен трактоваться как непрозрачный
тип и не иметь возможности прямого доступа.

Если хотя бы одна из переменных

sin_port
или
sin_addr
заполнена байтами
\0
(обычно функцией
memset
), то это указывает на условие "пренебречь". Серверные процессы, как правило, не беспокоятся о том, какой IP-адрес используется для локального соединения. Другими словами, они согласны принимать соединения с любым адресом, имеющимся на данной машине. Если в приложении требуется принимать соединения только на одном интерфейсе, то при этом нужно обязательно указать адрес. Такой адрес иногда называется неустановленным, поскольку он не представляет собой полное определение адреса соединения (для него требуется еще IP-адрес) [131] .

131

Значения для неустановленных IPv4-адресов содержатся в константе

INADDR_ANY
, которая является 32-битным числом.

17.5.3. Адресация IPv6

В IPv6 используется тот же самый кортеж (локальный хост, локальный порт, удаленный хост, удаленный порт), что и в IPv4, и одни и те же номера портов (16-битные значения).

IPv6-адреса локального и удаленного хостов являются 128-битными (16-байтовыми) числами вместо 32-битных чисел, которые использовались в IPv4. Применение таких больших адресов обеспечивает протоколы достаточным количеством адресов для будущего развития (можно без проблем предоставить уникальный адрес каждому атому в Млечном Пути). На первый взгляд, это может показаться избыточной тратой ресурсов. Однако сетевые архитектуры имеют склонность небрежно относиться к адресам и растрачивать огромное их число впустую, поэтому разработчики версии IPv6 предпочли перейти к 128-битным адресам сейчас, чем переживать о возможной необходимости изменять адреса в будущем.

Аналогом десятичного представления с разделителями-точками, которое используется в IPv4, для версии IPv6 является представление с разделителями-двоеточиями. Как подсказывает название, двоеточия отделяют каждую пару байтов в адресе (вместо точки, которая отделяет каждый отдельный байт). Из-за большой длины IPv6-адреса записываются в шестнадцатеричной (а не в десятичной) форме, что помогает уменьшить их длину. Ниже показано несколько примеров того, как выглядит IPv6-адрес в представлении с разделителями-двоеточиями [132] .

132

Эти примеры взяты из документа RFC 1884, в котором определена структура адресации IPv6.

1080:0:0:0:8:800:200С:417А

FF01:0:0:0:0:0:0:43

0:0:0:0:0:0:0:1

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

1080::8:800:200C:417A

FF01::43

::1

Если рассмотреть самый крайний случай, то адрес

0:0:0:0:0:0:0:0
превращается просто в выражение
::
[133] .

Последний метод записи IPv6-адресов заключается в том, что последние 32 бита представляются с разделительными точками, а первые 96 битов — с разделительными двоеточиями. При этом адрес обратной связи IPv6

::1
будет записан либо как
::0.0.0.1
, либо как
0:0:0:0:0:0:0.0.0.1
.

133

Это так называемый неустановленный адрес для IPv6.

IPv6 определяет любой адрес с 96 начальными нулями (за исключением адреса обратной связи и неустановленного адреса) как совместимый IPv4-адрес, который позволяет сетевым маршрутизаторам передавать через сети IPv6 пакеты, предназначенные для IPv4-хостов. Сокращение двоеточий позволяет легко записать IPv4-адрес как IPv6-адрес путем добавления

::
перед стандартным десятичным адресом с точками. Такой тип адресов называется IPv4-совместимым IPv6-адресом. Такая адресация применяется только маршрутизаторами; обычные программы не могут воспользоваться ее преимуществами.

Программы, работающие на машинах IPv6 и требующие обращения к машинам IPv4, могут использовать отображенные IPv4-адреса. Они дополняют IPv4-адрес 80-ю нулевыми старшими разрядами и 16-битным значением

0xffff
, которое записывается как
::ffff:
, а за ним следует десятичный IPv4-адрес с точками. Подобная адресация позволяет большинству программ в системе, поддерживающей только версию IPv6, явно общаться с узлами IPv4.

IPv6-адреса хранятся в переменных типа

struct sockaddr_in6
.

#include <sys/socket.h>

#include <netinet/in.h>

struct sockaddr_in6 {

 short int sin6_family; /* AF_INET6 */

 unsigned short int sin6_port; /* номер порта */

 unsigned int sin6_flowinfo; /* информация о потоке обмена IPv6 */

 struct in6_addr sin6_addr; /* IP-адрес */

 unsigned int sin6_scope_id; /* набор граничных интерфейсов */

}

Данная структура подобна

struct sockaddr_in
; здесь первый член сохраняет семейство адресов (в этом примере
AF_INET6
), а следующий — 16-битный номер порта в сетевом порядке байтов.

Четвертый член содержит двоичное представление IPv6-адреса, выполняя те же самые функции, что и последний член структуры

struct sockaddr_in
. Оставшиеся два элемента
sin6_flowinfo
и
sin6_scope_id
используются в более сложных задачах и для большинства приложений должны быть равны нулю.

Стандарты ограничивают

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

17.5.4. Манипулирование IP-адресами

В приложениях нередко требуется преобразовывать IP-адреса из удобочитаемых для человека представлений (либо десятичное с разделителями-точками, либо с разделителями-двоеточиями) в двоичное представление

struct in_addr
и наоборот. Функция
inet_ntop
принимает двоичный IP-адрес и возвращает указатель на строку, содержащую десятичную форму с точками или двоеточиями.

Поделиться с друзьями: