Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
28
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать
    1. Адресация сокетов

Для каждого из доменов адресов предназначена своя структура и свой собственный заголовочный файл. Например, для AF_UNIX - sockaddr_un, для AF_INET - sockaddr_in, для AF_X25 - sockaddr_x25 и так далее, хотя стандартизованы только первые два типа. Один из подходов к созданию структуры состоит в использовании адресации типа AF_UNIX. Он заключается в том, чтобы разместить в памяти специфическую структуру, заполнить необходимые поля и передать указатель на нее системному вызову bind или connect, попутно приведя указатель к типу struct sockaddr*.

С точки зрения переносимости программ, оптимальный набор – использовать для хранения адресов сокетов переменные типа sockaddr_storage, который гарантирует достаточный объем пространства в памяти под адрес любого типа:

  • если известно, с каким доменом адресов предстоит работать, то объявляете переменную соответствующего типа (например, sockaddr_un) или размещаете ее в динамической памяти (например, с помощью malloc);

  • если необходимо предусмотреть возможность создания сокетов с адресацией любого типа, то используете тип sockaddr_storage, но при обращении к таким переменным необходимо будет выполнять приведение к конкретному типу;

  • при обращении к системным вызовам bind и connect приходится выполнять приведение типа в соответствии с их прототипами.

Далее приводится пример использования последних двух правил:

struct sockaddr_storage sas;

struct sockaddr_un *sa = (struct sockaddr_un *)&sas;

sa->sun_family = AF_UNIX;

……………

bind(fd, (struct sockaddr_un *)sa, sizeof(*sa));

Рассмотрим домен адресов AF_UNIX:

struct sockaddr_un - структура адреса AF_UNIX

#include <sys/un.h>

struct sockaddr_un {

sa_family_t sun_family; /* AF_UNIX */

char sun_path[X]; /* имя */

};

Фактический размер имени обозначен X, потому что он зависит от типа операционной системы. В большинстве случаев длина имени не превышает 90 байт.

Рассмотрим домен адресов AF_INET, который предназначен для организации взаимодействий через Интернет или через локальную сеть. Ниже приводится описание структуры адресов из этого домена:

struct sockaddr_in - структура адресов из домена AF_INET

#include <netinet/in.h>

struct sockaddr_in {

sa_family_t sin_family; /* AF_INET */

In_port_t sin_port; /* номер порта (uint16_t) */

struct in_addr sin_addr; /* адрес IPv4 */

};

struct in_addr {

In_addr_t s_addr; /* адрес iPv4 (uint32_t) */

};

Адрес IPv4 (чаще его называют просто IP-адрес) представляет собой 32-битное число, обозначающее адрес сетевого интерфейса. Для записи этого числа чаще всего используется точечная нотация, в которой байты числа записываются отдельно друг от друга и отделяются символом точки, например, 216.109.125.70. Но и такой способ записи адресов зачастую оказывается неудобным, поэтому, как правило, используются описательные имена, например, www.nsuem.ru.

Каждый IP-адрес может быть связан с набором служб, каждая из которых имеет свой собственный номер порта. Значительная часть портов привязана к определенным службам. Например, HTTP – серверы работают с портом 80, FTP – серверы - с портом 21, серверы telnet - с портом 23. Можно увидеть соответствие служб и номеров портов в файле /etc/services. Для номера порта и IP-адреса определены типы in_port_t и in_addr_t, которые фактически являются типами uint16_t и uint32_t соответственно, а порядок следования байт в них должен соответствовать сетевому порядку. Для адресов, записываемых в точечной нотации, существует более удобная функция, которая преобразует строку с адресом в целое число с сетевым порядком следования байт:

inet_addr - преобразует строку с IP-адресом, записанным в точечной нотации, в целое число

#include <arpa/inet.h>

in_addr_t inet_addr (

const char *cp /* IP – адрес в точечной нотации */

);

/* Возвращает IP – адрес в виде (in_addr_t) или -1 в случае ошибки */

Возвращаемое значение -1, приведенное к типу in_addr_t, в точности соответствует IP-адресу 255.255.255.255. Но это вполне приемлемо, так как такой адрес считается неправильным при любых условиях. Функция, выполняющая обратное преобразование:

inet_ntoa - преобразует целое число, представляющее адрес IPv4, в строку

#include <arpa/inet.h>

char *inet_ntoa (

struct in_addr in /* целое число, представляющее адрес */

);

/* Возвращает строку */

Рассмотрим пример программы, которая выполняет соединение с HTTP – сервером на порте 80, запрашивает Web – страницу и отображает то, что будет принято от сервера.

#define REQUEST “GET / HTTP/1.0\r\n\r\n”

int main(void)

{

struct sockaddr_in sa;

int fg_skt;

char buf[1000];

ssize_t nread;

sa.sin_family = AF_INET;

sa.sin_port = htons(80);

sa.sin.addr.s_addr = inet_addr(“216.109.125.70”);

fd_skt = socket(AF_INET, SOCK_STREAM, 0);

connect(fd_skt, (struct sockaddr *)&sa, sizeof(sa));

write(fd_skt, buf, sizeof(buf));

(void)write(STDOUT_FILENO, buf, nread);

close(fg_skt);

exit(EXIT_SUCCESS);

EC_CLEANUP_BGN

exit(EXIT_FAILURE);

EC_CLEANUP_END

}

Запрос представляет собой команду GET, которая определена протоколом HTTP. Ниже приводится часть того, что вывела программа, здесь без труда можно узнать начальную страничку Yahoo:

HTTP/1.1 200 OK

Date: Sat, 19 Jul 2003 18:51:56 GMT

P3P: policyref=http://p3p.yahoo.com/w3c/p3p.xml, CP=”CAO DSP COR CUR ADM…”

Cache-Control: private

Content-Type: text/html

<html><head>

<title>Yahoo!</title>