Марк Митчелл - Программирование для Linux. Профессиональный подход
% rm /tmp/fifo
Создание FIFO-файлаFIFO-файл можно создать программным путем с помощью функции mkfifo(). Первым аргументом является путь к файлу. Второй аргумент задает права доступа к каналу со стороны его владельца, группы и остальных пользователей (об этом пойдет речь в разделе 10.3, "Права доступа к файлам"). Поскольку у канала есть читающая и записывающая стороны, права доступа должны учитывать оба случая. Если канал не может быть создан (например, файл с таким именем уже существует), функция mkfifo() возвращает -1. Для работы функции требуется подключить к программе файлы <sys/types.h> и <sys/stat.h>.
Доступ к FIFO-файлуК FIFO-файлу можно обращаться как к обычному файлу. При организации межзадачного взаимодействия одна программа должна открыть файл для записи, а другая - для чтения. Над файлом можно выполнять как низкоуровневые (open(), write(), read(), close() и др.), так и высокоуровневые (fopen(), fprintf(), fscanf(), fclose() и др.) функции.
Например, на низком уровне запись блока данных в FIFO-файл осуществляется следующим образом:
int fd = open(fifo_path, O_WRONLY);
write(fd, data, data_length);
close(fd);
А так выполняется чтение строки из FIFO-файла на высоком уровне:
FILE* fifo = fopen(fifo_path, "r");
fscanf(fifo, "%s", buffer);
fclose(fifo);
У FIFO-файла одновременно может быть несколько читающих и записывающих программ. Входные потоки разбиваются на атомарные блоки, размер которых определяется константой PIPE_BUF (4 Кбайт в Linux). Если несколько программ параллельно друг другу осуществляют запись в файл, их блоки будут чередоваться. То же самое относится к программам. одновременно читающим данные из файла.
Отличия от именованных каналов в WindowsКаналы операционных систем семейства Win32 очень напоминают каналы Linux. Основное различие касается именованных каналов, которые в Win32 функционируют скорее как сокеты. Именованные каналы Win32 способны соединять по сети процессы, выполняющиеся на разных компьютерах. В Linux для этой цели используются именно сокеты. Кроме того, в Win32 допускается, чтобы несколько программ чтения или записи работали с именованным каналом, не перекрывая потоки друг друга, а сами каналы поддерживают двунаправленный обмен данными.[17]
5.5. Сокеты
Сокет — это устройство двунаправленного взаимодействия, которое предназначено для связи с другим процессом, выполняющимся на этом же или на другом компьютере. Сокеты используются Internet-программами, такими как telnet, rlogin, ftp, talk и Web-броузеры.
Например, с помощью программы telnet можно получить от Web-сервера HTML-страницу, поскольку обе программы общаются по сети при помощи сокетов. Чтобы установить соединение с Web-сервером www.codesourcery.com, следует ввести команду telnet www.codesourcery.com 80. Загадочная константа 80 обозначает порт, который прослушивается Web-сервером. Когда соединение будет установлено, введите команду GET /. В результате через сокет будет послан запрос Web-серверу, который в ответ вернет начальную HTML-страницу, после чего закроет соединение.
% telnet www.codesourcery.com 80
Trying 206.168.99.1...
Connected to merlin.codesourcery.com (206.168.99.1).
Escape character is '^]'.
GET /
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset="iso-8659-1">
...
5.5.1. Концепции сокетов
При создании сокета необходимо задать три параметра, тип взаимодействия, пространство имен и протокол.
Тип взаимодействия определяет способ интерпретации передаваемых данных и число абонентов. Данные, посылаемые через сокет, формируются в блоки, называемые пакетами. Тип взаимодействия указывает на то, как обрабатываются пакеты и как они передаются от отправителя к получателю.
■ При взаимодействии с установлением соединения гарантируется доставка пакетов в том порядке, в каком они были отправлены. Если пакеты теряются или приходят в неправильном порядке из-за проблемы в сети, принимающая сторона автоматически запрашивает у отправителя повторную отправку данных.
Сокеты, ориентированные на соединения, функционируют наподобие телефонного звонка: адреса запрашивающей и принимающей сторон фиксируются в самом начале, на этапе установки соединения.
■ При передаче дейтаграмм не гарантируется доставка и правильный порядок пакетов. Пакеты могут теряться и приходить в произвольном порядке. Операционная система лишь обещает сделать "все возможное".
Дейтаграммные сокеты функционируют подобно почтовой службе: отправитель указывает адрес получателя каждого сообщения и не контролирует доставку пакетов.
Пространство имен сокета определяет способ записи адресов. Например, в локальном пространстве имен адреса — это обычные имена файлов. В пространстве имен Internet адрес сокета состоит из IP-адреса компьютера, подключенного к сети, и номера порта. Благодаря номерам портов можно различать сокеты, созданные на одном компьютере.
Протокол определяет способ передачи данных. Основными семействами протоколов являются TCP/IP (ключевые сетевые протоколы, используемые в Internet) и AppleTalk (протоколы, используемые системами Macintosh). Сокеты могут также работать в соответствии с локальным коммуникационным протоколом UNIX. Не все комбинации типов взаимодействия, пространств имен и протоколов поддерживаются.
5.5.2. Системные вызовы
Сокеты являются более гибкими в управлении, чем рассмотренные выше механизмы межзадачного взаимодействия. При работе с сокетами используются следующие функции:
■ socket() — создает сокет;
■ close() — уничтожает сокет;
■ connect() — устанавливает соединение между двумя сокетами;
■ bind() — назначает серверному сокету адрес;
■ listen() — переводит сокет в режим приема запросов на подключение;
■ accept() — принимает запрос на подключение и создает новый сокет, который будет обслуживать данное соединение.
Сокеты представляются в программе файловыми дескрипторами.
Создание и уничтожение сокетовФункции socket() и close() создают и уничтожают сокет соответственно. В первом случае необходимо задать три параметра: пространство имен, тип взаимодействия и протокол. Константы, определяющие пространство имен, начинаются с префикса PF_ (сокращение от "protocol family" — семейство протоколов). Например, константы PF_LOCAL и PF_UNIX соответствуют локальному пространству имен, а константа PF_INET — пространству имен Internet. Константы, определяющие тип взаимодействия, начинаются с префикса SOCK_. Сокетам, ориентированным на соединения, соответствует константа SOCK_STREAM, а дейтаграммным сокетам — константа SOCK_DGRAM.
Выбор протокола определяется связкой "пространство имен — тип взаимодействия". Поскольку для каждой такой пары, как правило, лучше всего подходит какой-то один протокол, в третьем параметре функции socket() обычно задается значение 0 (выбор по умолчанию). В случае успешного завершения функция socket() возвращает дескриптор сокета. Чтение и запись данных через сокеты осуществляется с помощью обычных файловых функций, таких как read(), write() и т.д. По окончании работы с сокетом его необходимо удалить с помощью функции close().
Вызов функции connect()Чтобы установить соединение между двумя сокетами, следует на стороне клиента вызвать функцию connect(), указав адрес серверного сокета. Клиент — это процесс, инициирующий соединение, а сервер — это процесс, ожидающий поступления запросов на подключение. В первом параметре функции connect() задается дескриптор клиентского сокета, во втором— адрес серверного сокета, в третьем — длина (в байтах) адресной структуры, на которую ссылается второй параметр. Формат адреса будет разным в зависимости от пространства имен.
Передача данныхПри работе с сокетами можно применять те же самые функции, что и при работе с файлами. О низкоуровневых функциях ввода-вывода, поддерживаемых в Linux, рассказывается в приложении Б, "Низкоуровневый ввод-вывод". Имеется также специальная функция send(), являющаяся альтернативой традиционной функции write().
5.5.3. Серверы
Жизненный цикл сервера можно представить так:
1) создание сокета, ориентированного на соединения (функция socket());
2) назначение сокету адреса привязки (функция bind());
3) перевод сокета в режим ожидания запросов (функция listen());