Андрей Робачевский - Операционная система UNIX
- Название:Операционная система UNIX
- Автор:
- Жанр:
- Издательство:BHV - Санкт-Петербург
- Год:1997
- Город:Санкт-Петербург
- ISBN:5-7791-0057-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Андрей Робачевский - Операционная система UNIX краткое содержание
Книга посвящена семейству операционных систем UNIX и содержит информацию о принципах организации, идеологии и архитектуре, объединяющих различные версии этой операционной системы.
В книге рассматриваются: архитектура ядра UNIX (подсистемы ввода/вывода, управления памятью и процессами, а также файловая подсистема), программный интерфейс UNIX (системные вызовы и основные библиотечные функции), пользовательская среда (командный интерпретатор shell, основные команды и утилиты) и сетевая поддержка в UNIX (протоколов семейства TCP/IP, архитектура сетевой подсистемы, программные интерфейсы сокетов и TLI).
Для широкого круга пользователей
Операционная система UNIX - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Однако потеря данных может вызвать ответное молчание. Для обработки подобной ситуации отправитель должен установить таймер и повторно передать данные по тайм-ауту, начиная с последнего подтверждения. Данный механизм является запасным и гарантирует повторную передачу, хотя и вызывает довольно большие задержки.
Программные интерфейсы
Программный интерфейс сокетов
Вы уже познакомились с интерфейсом сокетов при обсуждении реализации межпроцессного взаимодействия в BSD UNIX. Поскольку сетевая поддержка впервые была разработана именно для BSD UNIX, интерфейс сокетов и сегодня является весьма распространенным при создании сетевых приложений. В разделе "Поддержка сети в BSD UNIX" мы вновь вернемся к сокетам, когда будем рассматривать внутреннюю архитектуру сетевой подсистемы в UNIX ветви BSD. Сейчас же рассмотрим простой пример приложения клиент-сервер, который демонстрирует возможности сокетов при обеспечении взаимодействия между удаленными процессами. Несмотря на то что взаимодействие затрагивает передачу данных по сети, приведенная программа мало отличается от примера, рассмотренного в разделе "Межпроцессное взаимодействие в BSD UNIX. Сокеты" главы 3. Логика приложения сохранена — клиент отправляет серверу сообщение, сервер передает его обратно, а клиент, в свою очередь, выводит полученное сообщение на экран. Наиболее существенным отличием является коммуникационный домен сокетов — в данном случае AF_INET
. Соответственно изменилась и схема адресации коммуникационного узла. Согласно схеме адресации TCP/IP, коммуникационный узел однозначно идентифицируется двумя значениями: адресом хоста (IP-адрес) и адресом процесса (адрес порта). Это отражает и структура sockaddr_in
, которая является конкретным видом общей структуры адреса сокета sockaddr
. Структура sockaddr_in
имеет следующий вид:
struct sockaddr_in {
short sin_family;
Коммуникационный домен — AF_INET
u_short sin_port;
Номер порта
struct in_addr sin_addr;
IP-адрес хоста
char sin_zero[8];
};
Адрес порта должен быть предварительно оговорен между клиентом и сервером.
В заключение, прежде чем перейти непосредственно к текстам программы, заметим, что интерфейс сокетов также поддерживается и в UNIX System V, наряду с другим программным интерфейсом — TLI, который будет рассмотрен в следующем разделе.
Приведенный пример в качестве транспортного протокола использует TCP. Это значит, что перед передачей прикладных данных клиент должен установить соединение с сервером. Эта схема, приведенная на рис. 6.17, несколько отличается от рассмотренной в разделе "Межпроцессное взаимодействие в BSD UNIX. Сокеты", где передача данных осуществлялась без предварительного установления связи и в данном случае соответствовала бы использованию протокола UDP.

Рис. 6.17. Схема установления связи и передачи данных между клиентом и сервером
В соответствии с этой схемой сервер производит связывание с портом, номер которого предполагается известным для клиентов bind(2) , и сообщает о готовности приема запросов listen(2) ). При получении запроса он с помощью функции accept(2) создает новый сокет, который и обслуживает обмен данными между клиентом и сервером. Для того чтобы сервер мог продолжать обрабатывать поступающие запросы, он порождает отдельный процесс на каждый поступивший запрос. Дочерний процесс, в свою очередь, принимает сообщения от клиента ( recv(2) ) и передает их обратно ( send(2) ).
Клиент не выполняет связывания, поскольку ему безразлично, какой адрес будет иметь его коммуникационный узел. Эту операцию выполняет система, выбирая свободный адрес порта и установленный адрес хоста. Далее клиент направляет запрос на установление соединения ( connect(2) ), указывая адрес сервера (IP-адрес и номер порта). После установления соединения ("тройное рукопожатие") клиент передает сообщение ( send(2) ), принимает от сервера ответ recv(2) ) и выводит его на экран.
В программе используются несколько функций, которые не рассматривались. Эти функции значительно облегчают жизнь программисту, выполняя, например, такие действия, как трансляцию доменного имени хоста в его IP-адрес ( gethostbyname(3N) ), приведение в соответствие порядка следования байтов в структурах данных, который может различаться для хоста и сети ( htons(3N) ), а также преобразование IP-адресов и их составных частей в соответствии с привычной "человеческой" нотацией, например 127.0.0.1 ( inet_ntoa(3N) ). Мы не будем подробнее останавливаться на этих функциях, предоставляя читателю самостоятельно обратиться к соответствующим разделам электронного справочника man(1) .
Ниже приведены тексты программ сервера и клиента.
#include
#include
#include
#include
#include
#include
#include
/* Номер порта сервера, известный клиентам */
#define PORTNUM 1500
main(argc, argv)
int argc;
char *argv[];
{
int s, ns;
int pid;
int nport;
struct sockaddr_in serv_addr, clnt_addr;
struct hostent* hp;
char buf[80], hname[80];
/* Преобразуем порядок следования байтов
к сетевому формату */
nport = PORTNUM;
nport = htons((u_short)nport);
/* Создадим сокет, использующий протокол TCP */
if ((s=socket(AF_INET, SOCK_STREAM, 0))==-1) {
perror("Ошибка вызова socket()");
exit(1);
}
/* Зададим адрес коммуникационного узла */
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv.addr.sin_port = nport;
/* Свяжем сокет с этим адресом */
if (bind(s, struct sockaddr*)&serv_addr,
sizeof(serv_addr))==-1) {
perror("Ошибка вызова bind()");
exit(1);
}
/* Выведем сообщение с указанием адреса сервера */
fprintf(stderr, "Сервер готов: %s\n",
inet_ntoa(serv_addr.sin_addr));
/* Сервер готов принимать запросы
на установление соединения.
Максимальное число запросов, ожидающих обработки – 5.
Как правило, этого числа достаточно, чтобы успеть
выполнить accept(2) и породить дочерний процесс */
if (listen(s, 5)==-1) {
perror("Ошибка вызова listen()");
exit(1);
}
/* Бесконечный цикл получения запросов и их обработки */
while (1) {
int addrlen;
bzero(&clnt_addr, sizeof(clnt_addr));
addrlen = sizeof(clnt_addr);
/* Примем запрос. Новый сокет ns становится
коммуникационным узлом созданного виртуального канала */
if ((ns=accept(s, (struct sockaddr*)&clnt_addr,
Интервал:
Закладка: