Парные сокеты
Сокеты в файловом пространстве имен похожи на именованные каналы тем, что для идентификации сокетов используются файлы специального типа. В мире сокетов есть и аналог неименованных каналов – парные сокеты (socket pairs). Как и не именованные каналы, парные сокеты создаются парами и не имеют имен. Естественно, что область применения парных сокетов – та же, что и у неименованных каналов, - взаимодействие между родительским и дочерним процессом. Так же как и в случае неименованного канала, один из дескрипторов используется одним процессом, другой – другим. В качестве примера использования парных сокетов мы рассмотрим программу sockpair.c, создающую два процесса с помощью fork(). Дочерние процессы sockpair.c используют парные сокеты для обмена вежливым английским приветствием.
#include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define STR1 "How are you?" #define STR2 "I'm ok, thank you." #define BUF_SIZE 1024 int main(int argc, char ** argv) { int sockets[2]; char buf[BUF_SIZE]; int pid; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) { perror("socketpair() failed"); return EXIT_FAILURE; } pid = fork(); if (pid != 0) { close(sockets[1]); write(sockets[0], STR1, sizeof(STR1)); read(sockets[0], buf, sizeof(buf)); printf("%s\n", buf); close(sockets[0]); } else { close(sockets[0]); read(sockets[1], buf, sizeof(buf)); printf("%s\n", buf); write(sockets[1], STR2, sizeof(STR2)); close(sockets[1]); } }
Парные сокеты создаются функцией socketpair(2). У функции socketpair() четыре параметра. Первые три параметра функции те же, что и у socket(), а четвертым параметром является массив из двух переменных, в которых возвращаются дескрипторы. Дескрипторы сокетов, возвращенные socketpair(), уже готовы к передаче данных, так что мы сразу можем применять к ним функции read()/write(). После вызова fork() каждый процесс получает оба дескриптора, один из которых он должен закрыть. Для закрытия сокета мы используем функцию close().
При взгляде на интерфейс программирования парных сокетов может возникнуть вопрос, а почему собственно эти функции относятся к сокетам? Ведь при работе с ними мы не используем ни адреса, ни модель клиент-сервер. Это верно, но заметьте, что функции socketpair() передаются значения домена и типа сокета, так что и формально, и с точки зрения реализации в системе мы используем настоящие сокеты. Следует отметить, что указание домена в функции socketpair() выглядит явно излишне, поскольку для этой функции система поддерживает только сокеты в домене AF_UNIX (вполне логичное ограничение, если учесть, что парные сокеты не имеют имен и предназначены для обмена данными между родственными процессами).