
- •Введение
- •Глава 1. Фундаментальные концепции unix Систем
- •Программы, процессы и потоки
- •Сигналы
- •Идентификаторы процессов, группы процессов и сеансы
- •Система прав
- •Другие атрибуты процесса
- •Межпроцессное взаимодействие
- •Использование системных вызовов
- •Краткие описания функций и обработка ошибок
- •Контрольные вопросы
- •Литература
- •Глава 2. Базовые операции ввода-вывода
- •Файловые операции ввода - вывода
- •Стандартные дескрипторы
- •Системные вызовы open и creat
- •Системный вызов umask
- •Системный вызов unlink
- •Текущая позиция в файле
- •Системный вызов write
- •2.8. Системный вызов read
- •2.9. Системный вызов close
- •2.10. Системный вызов lseek
- •2.11. Системные вызовы pread и pwrite
- •2.12. Системные вызовы truncate и ftruncate
- •Контрольные вопросы
- •Литература
- •Глава 3. Дополнительные операции файлового ввода_вывода
- •Низкоуровневый доступ к файловой системе
- •Жесткие и символические ссылки
- •Системный вызов getcwd
- •Отображение метаданных файла
- •Системные вызовы getpwuid, getgrgid и getlogin
- •Каталоги
- •Системные вызовы chdir и fchdir
- •Системные вызовы mkdir и rmdir
- •Контрольные вопросы
- •Литература
- •Глава 4. Процессы и потоки
- •4.1. Среда окружения
- •Системный вызов exec
- •Системный вызов fork
- •Завершение процесса и системные вызовы exit
- •Системные вызовы wait, waitpid и waitid
- •Получение и изменение идентификаторов пользователя и группы
- •Получение и изменение приоритета
- •Контрольные вопросы
- •Литература
- •Глава 5. Механизмы межпроцессного взаимодействия
- •5.1. Каналы
- •5.2. Системные вызовы dup и dup2
- •5.3. Двунаправленное взаимодействие с использованием однонаправленных каналов
- •Контрольные вопросы
- •Литература
- •Глава 6.Механизмы взаимодействия процессов
- •Именованные каналы (fifo)
- •Системные вызовы для работы с очередями сообщений posix
- •Семафоры
- •Системные вызовы для работы с общей памятью posix
- •Контрольные вопросы
- •Литература
- •Глава 7.Сетевое взаимодействие и сокеты
- •Основные системные вызовы для работы с сокетами, образующими логические соединения
- •Обслуживание нескольких клиентов
- •Адресация сокетов
- •In_port_t sin_port; /* номер порта (uint16_t) */
- •In_addr_t s_addr; /* адрес iPv4 (uint32_t) */
- •Домен адресов af_inet6
- •In_port_t sin6_port; /* номер порта (uint16_t) */
- •Доменная система именования
- •Параметры сокетов
- •Контрольные вопросы
- •Литература
- •Глава 8.Сигналы и таймеры
- •Введение в сигналы
- •Жизненный цикл сигналов
- •Типы сигналов
- •Системный вызов sigaction
- •Контрольные вопросы
- •Литература
- •Заключение
- •Список литературы
- •Глава 2. Базовые операции ввода-вывода 14
- •Глава 3. Дополнительные операции файлового ввода_вывода 25
- •Глава 6. Механизмы взаимодействия процессов 58
Адресация сокетов
Для каждого из доменов адресов предназначена своя структура и свой собственный заголовочный файл. Например, для 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>