- •Введение
- •Глава 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
Контрольные вопросы
Охарактеризуйте достоинства и недостатки семафоров.
Охарактеризуйте достоинства и недостатки общей памяти.
Охарактеризуйте достоинства и недостатки очередей сообщений.
Охарактеризуйте достоинства и недостатки именованных каналов.
Назовите основные отличия именованных каналов от неименованных.
Литература
Глас Г., Эйблс К. Unix для программистов и пользователей. / Г. Глас, К. Эйблс – СПб.: БХВ-Петербург, 2004. – 848 с.: ил.
Брюс М. Unix/Linux: Теория и практика программирования. / М.Брюс – Издательство: Кудиц-Образ, 2004. -576 с.
Стивенс У.Р. UNIX. Профессиональное программирование. / У.Р. Стивенс. – Издательство: Символ-Плюс, 2007. - 1040 с.
Глава 7.Сетевое взаимодействие и сокеты
Основной способ организации обмена информацией между компьютерами, объединенными в сеть, - сокеты. Для работы с ними существует восемь основных системных вызовов, пять из которых предназначены исключительно для сокетов: socket, bind, listen, accept, connect, read, write и close. Учитывая всю сложность сетевых взаимодействий и многообразие протоколов связи, существует еще около 60 системных вызовов, имеющих отношение к сокетам.
Сокеты
Процесс может открыть именованный канал таким образом: fd = open(“MyFifo”, O_RDONLY);
Этот системный вызов делает следующее:
Создает объект для операций ввода-вывода и назначает ему файловый дескриптор.
Связывает файловый дескриптор с внешним именем MyFifo.
Ожидает, пока кто-нибудь, не откроет канал на запись.
Возвращает файловый дескриптор, который затем может быть использован в системном вызове read.
Аналогичным образом работают и сокеты, только каждый шаг выделен в отдельный системный вызов:
Socket - создает объект (сокет) и назначает ему файловый дескриптор.
Bind – устанавливает адрес (имя) сокета, чтобы другой процесс мог сослаться на него.
Listen – помечает сокет как предназначенный для приема запросов на соединение от других сокетов.
Accept – блокируется в ожидании запроса на соединение.
Connect – устанавливает соединение с сокетом, который был заблокирован на accept.
Последовательность создания и инициализации сокетов на стороне сервера отличается от последовательности действий на стороне клиента.
На стороне сервера:
вызывается socket для создания объекта и связанного с ним файлового дескриптора;
вызывается bind, для назначения сокету адреса;
вызывается listen, чтобы пометить сокет, как предназначенный для приема запросов на соединение;
вызывается accept, чтобы дождаться и принять входящее сообщение. После этого вызов accept создает второй сокет с новым файловым дескриптором;
в операциях ввода-вывода участвует вновь созданный файловый дескриптор.
На стороне клиента:
вызывается socket для создания объекта и связанного с ним файлового дескриптора;
для установления соединения с сервером вызывается connect, которому в качестве аргумента передается имя сервера;
файловый дескриптор сокета используется для выполнения операций ввода-вывода.
Рассмотрим программу порождения дочернего процесса, который будет выступать в роли клиента, а родительский процесс – в роли сервера:
#define SOCKETNAME “MySocket”
int main(void)
{
struct sockaddr_un sa;
(void)unlink(SOCKETNAME);
strcpy(sa.sun_path, SOCKETNAME);
sa.sun_family = AF_UNIX;
if (fork() == 0) { /*потомок-клиент */
int fd_skt;
char buf[100];
fd_skt = socket(AF_UNIX, SOCK_STREAM, 0);
while (connect(fd_skt, (struct sockaddr *)&sa, sizeof(sa)) == -1)
if (errno == ENOENT) {
sleep(1);
continue;
}
else
EC_FAIL
write(fd_skt, “Привет!”, 7);
read(fd_skt, buf, sizeof(buf));
printf(“Клиент получил сообщение” \”%s\”\n”, buf);
close(fd_skt);
exit(EXIT_SUCCESS);
}
else { /*предок-сервер */
int fd_skt, fd_client;
char buf[100];
fd_skt = socket(AF_UNIX, SOCK_STREAM, 0);
bind(fd_skt, (struct sockaddr *)&sa, sizeof(sa));
listen(fd_skt,SOMAXCONN);
fd_client = accept(fd_skt, NULL, 0);
read(fd_client, buf, sizeof(buf));
printf(“Сервер получил сообщение” \”%s\”\n”, buf);
write(fd_client, “Пока!”, 9);
close(fd_skt);
close(fd_client);
exit(EXIT_SUCCESS);
}
EC_CLEANUP_BGN
exit(EXIT_FAILURE);
EC_CLEANUP_END
}
Первое, что мы видим, - адрес (имя), которое передается системным вызовам bind и connect. Он представляет собой не просто строку, а целую структуру, которая хранит строку в поле sun_path, и домен адресов – в поле sun_family. Домен AF_UNIX означает локальное взаимодействие ограниченное рамками одной системы. Системный вызов bind не может повторно использовать существующие имена для сокетов типа AF_UNIX, поэтому производится удаление имени, чтобы гарантировать его отсутствие. Сервер (родительский процесс) выполняет последовательность из шести шагов. Клиент (дочерний процесс) также следует заданной последовательности действий, но с одним небольшим отступлением: если обращение к connect на стороне клиента произойдет раньше, чем сервер обратится к bind, вызов connect потерпит неудачу, поскольку ему не с кем будет устанавливать соединение. Поэтому в случае получения ошибки клиент ненадолго засыпает и повторяет попытку.
Когда вызов accept возвращает управление, сервер выполняет операции ввода-вывода над вновь созданным (вторичным) файловым дескриптором. Клиент продолжает использовать свой дескриптор. Системные вызовы accept и connect могут быть заблокированы. Остальные возвращают управление в вызывающую программу немедленно, как только выполнят работу. Соединение может существовать сколь угодно долго, пока одна из сторон не разорвет его, и по своей сути напоминает двунаправленный неименованный канал. Файл сокета действительно является файлом, что видно в выводе команды ls:
$ ls -l MySocket
srwxr-xr-x 1 marc sysadmin 0 Apr 4 10:05 MySocket
В результате работы программы получилось следующее:
Сервер получил сообщение “Привет!”
Клиент получил сообщение “Пока!”