Программирование POSIX сокет. Сукиязов С.А. - 7 стр.

UptoLike

Составители: 

#include <sys/socket.h>
#include <resolv.h>
int connect(int sd, struct sockaddr * server, int addr_len);
Первый параметр (sd) представляет собой дескриптор сокета, который был создан функцией
socket(). Последний, третий, параметр задает длину структуры sockaddr, передаваемой во втором пара-
метре, так как она может иметь разный тип и размер. Это самый важный момент, делающий функцию
socket () принципиально отличной от функций файлового ввода-вывода.
Функция socket () поддерживает по крайней мере два домена
: PF_INET и PF_IPX. В каждом из се-
тевых доменов используется своя структура адреса. Все структуры являются производными от одного
общего предкаструктуры sockaddr. Именно она указана в заголовке функции connect().
Абстрактная структура sockaddr
Структура sockaddr является абстрактной в том смысле, что переменные данного типа почти нико-
гда не приходится создавать напрямую. Существует множество других, специализированных струк-
тур, приводимых к типу sockaddr. Подобная методика позволяет работать с адресами различного
формата по некоему общему образцу. Аналогичная абстракция используется при организации стеков. В
стек могут помещаться данные разных типов
, но к ним всегда применяются одинаковые операции:
push (занести), pop (извлечь) и т.д. Во всех структурах семейства sockaddr первое поле имеет суффикс
_family и интерпретируется одинаковым образом: оно задает семейство адреса, или сетевой домен.
Тип данного поля определяется как 16-разрядное целое число без знака.
Приведем общий вид структуры адреса и рядом для сравненияструктуру адреса в домене
PF_INET (взято из файлов заголовков):
struct sockaddr {
unsigned short int sa_family;
unsigned char sa_data[14];
};
struct sockaddr_in {
sa_family_t sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char __pad[];
}
Взаимосвязь между типом сокета и полем семейства адреса в структуре sockaddr
Тип домена, задаваемый в функции socket (), должен совпадать со значением, которое записывается в
первое поле- структуры sockaddr (за исключением префикса: в первом случае это PF_, во втором
AF_). Например, если в программе создается сокет PF INET6, то в первое поле структуры должно быть
помещено значение AF_INET6, иначе программа будет неправильно работать.
Обратите внимание: поля sa_family и sin_family в обеих структурах являются общими. Любая
функция, получающая подобного рода структуру, сначала проверяет первое поле. Следует также отме-
тить, что это единственное поле с серверным порядком следования байтов. Поля-заполнители (sa data и
pad) используются во многих структурах. По существующей договоренности структуры sockaddr и
sockaddr in должны иметь размер 16 байтов (в стандарте
IPv6 структура sockaddr_in6 имеет размер 24
байта), поэтому такие поля дополняют тело структуры незначащими байтами.
Необходимо обратить внимание что размер массива __pad[] не указан. Ничего неправильного в
этом неттаково общепринятое соглашение. Поскольку данный массив заполняется нулями, его раз-
мер не имеет значения (в случае структуры sockaddr_in он равен восьми байтам). В некоторых системах
в
структуре sockaddr in выделяются дополнительные поля для внутренних вычислений. Не стоит обра-
щать на них внимание, а также использовать их, поскольку нет гарантии, что эти поля будут поддержи-
ваться в другой системе. В любом случае достаточно инициализировать данную структуру нулями.
Ниже описано назначение полей структуры, а также приведены примеры их содержимого.
Поле Описание
Порядок байтов Пример
sin_family Семейство протоколов Серверный AF_INET
sin_port Номер порта сервера Сетевой 13
sin_addr IP-адрес сервера Сетевой 127.0.0.1
Прежде чем вызвать функцию connect(), программа должна заполнить описанные поля. В листин-
ге 1.2 показано, как это сделать (полный текст примера имеется на Web-узле). Вообще говоря, в Linux не
требуется приводить структуру sockaddr in к типу sockaddr. Если же предполагается использовать про-
грамму в разных системах, можно легко
добавить операцию приведения типа.
Приведение к типу sockaddr
В UNIX-системах любую структуру данного семейства можно привести к типу sockaddr. Это позво-
лит избежать получения предупреждений компилятора. В приводимых примерах данная операция не
используется только потому, что это делает примеры немного понятнее (да и Unux этого не требу-
ет).
#include 
#include 
int connect(int sd, struct sockaddr * server, int addr_len);
       Первый параметр (sd) представляет собой дескриптор сокета, который был создан функцией
socket(). Последний, третий, параметр задает длину структуры sockaddr, передаваемой во втором пара-
метре, так как она может иметь разный тип и размер. Это самый важный момент, делающий функцию
socket () принципиально отличной от функций файлового ввода-вывода.
      Функция socket () поддерживает по крайней мере два домена: PF_INET и PF_IPX. В каждом из се-
тевых доменов используется своя структура адреса. Все структуры являются производными от одного
общего предка — структуры sockaddr. Именно она указана в заголовке функции connect().
Абстрактная структура sockaddr
Структура sockaddr является абстрактной в том смысле, что переменные данного типа почти нико-
гда не приходится создавать напрямую. Существует множество других, специализированных струк-
тур, приводимых к типу sockaddr. Подобная методика позволяет работать с адресами различного
формата по некоему общему образцу. Аналогичная абстракция используется при организации стеков. В
стек могут помещаться данные разных типов, но к ним всегда применяются одинаковые операции:
push (занести), pop (извлечь) и т.д. Во всех структурах семейства sockaddr первое поле имеет суффикс
_family и интерпретируется одинаковым образом: оно задает семейство адреса, или сетевой домен.
Тип данного поля определяется как 16-разрядное целое число без знака.
     Приведем общий вид структуры адреса и рядом для сравнения — структуру адреса в домене
PF_INET (взято из файлов заголовков):
struct sockaddr {                                 struct sockaddr_in {
  unsigned short int sa_family;                     sa_family_t             sin_family;
  unsigned char sa_data[14];                        unsigned short int      sin_port;
};                                                  struct in_addr          sin_addr;
                                                    unsigned char           __pad[];
                                                  }

Взаимосвязь между типом сокета и полем семейства адреса в структуре sockaddr
Тип домена, задаваемый в функции socket (), должен совпадать со значением, которое записывается в
первое поле- структуры sockaddr (за исключением префикса: в первом случае это PF_, во втором —
AF_). Например, если в программе создается сокет PF INET6, то в первое поле структуры должно быть
помещено значение AF_INET6, иначе программа будет неправильно работать.
       Обратите внимание: поля sa_family и sin_family в обеих структурах являются общими. Любая
функция, получающая подобного рода структуру, сначала проверяет первое поле. Следует также отме-
тить, что это единственное поле с серверным порядком следования байтов. Поля-заполнители (sa data и
pad) используются во многих структурах. По существующей договоренности структуры sockaddr и
sockaddr in должны иметь размер 16 байтов (в стандарте IPv6 структура sockaddr_in6 имеет размер 24
байта), поэтому такие поля дополняют тело структуры незначащими байтами.
      Необходимо обратить внимание что размер массива __pad[] не указан. Ничего неправильного в
этом нет — таково общепринятое соглашение. Поскольку данный массив заполняется нулями, его раз-
мер не имеет значения (в случае структуры sockaddr_in он равен восьми байтам). В некоторых системах
в структуре sockaddr in выделяются дополнительные поля для внутренних вычислений. Не стоит обра-
щать на них внимание, а также использовать их, поскольку нет гарантии, что эти поля будут поддержи-
ваться в другой системе. В любом случае достаточно инициализировать данную структуру нулями.
      Ниже описано назначение полей структуры, а также приведены примеры их содержимого.
Поле             Описание                     Порядок байтов                 Пример
sin_family       Семейство протоколов         Серверный                      AF_INET
sin_port         Номер порта сервера          Сетевой                        13
sin_addr         IP-адрес сервера             Сетевой                        127.0.0.1

       Прежде чем вызвать функцию connect(), программа должна заполнить описанные поля. В листин-
ге 1.2 показано, как это сделать (полный текст примера имеется на Web-узле). Вообще говоря, в Linux не
требуется приводить структуру sockaddr in к типу sockaddr. Если же предполагается использовать про-
грамму в разных системах, можно легко добавить операцию приведения типа.
Приведение к типу sockaddr
В UNIX-системах любую структуру данного семейства можно привести к типу sockaddr. Это позво-
лит избежать получения предупреждений компилятора. В приводимых примерах данная операция не
используется только потому, что это делает примеры немного понятнее (да и Unux этого не требу-
ет).