Клиент:
#include
#include
#include < sys/un.h>
char *msg = "Здравствуй, Мир!\n";
#define MAXBUF 256
char buf[MAXBUF];
main() {
struct sockaddr_un serv_addr, clnt_addr;
int sockfd;
int saddrlen, caddrlen, msglen, n;
/* Установим адрес сервера, с которым мы будем обмениваться
данными. Для этого заполним структуру данных sockaddr_un,
которую будем использовать при отправлении данных серверу
с помощью вызова sendto(). Значение адреса известно
по предварительной договоренности */
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, "./echo.server");
saddrlen = sizeof(serv_addr.sun_family) +
strlen(serv_addr.sun_path);
/* Создадим сокет датаграмм */
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
printf("Невозможно создать сокет\n");
exit(1);
}
/* Необходимо связать сокет с некоторым локальным адресом,
чтобы сервер имел возможность возвратить посланное сообщение.
Этот адрес должен быть уникальным в пределах коммуникационного
домена - т.е. данной операционной системы. Для обеспечения
этого условия, воспользуемся функцией mktemp(3C), которая
возвращает уникальное имя, основанное на представленном
шаблоне и идентификаторе нашего процесса PID */
bzero(&clnt_addr, sizeof(clnt_addr));
clnt_addr.sun_family = AF_UNIX;
strcpy(clnt_addr.sun_path, "/tmp/clnt.XXXX");
mktemp(clnt_addr.sun_path);
caddrlen =
sizeof(clnt addr.sun_family) + strlen(clnt_addr.sun_path);
if (bind(sockfd, (struct sockaddr*)&clnt_addr,
caddrlen) < 0) {
printf("Ошибка связывания сокета\n");
exit(1);
}
/* Итак, отправляем сакраментальное приветствие */
msglen = strlen(msg);
if (sendto(sockfd, msg, msglen, 0,
(struct sockaddr*)&serv addr, saddrlen) != msglen) {
printf("Ошибка передачи сообщения\n");
exit(1);
}
/* Прочитаем эхо*/
if ((n = recvfrom(sockfd, buf, MAXBUF, 0, NULL, 0)) < 0) {
printf("Ошибка получения сообщения\n");
exit(1);
}
/* И выведем его на экран */
printf("Эхо: %s\n", buf);
/* Уберем за собой */
close(sockfd);
unlink(clnt_addr.sun_path);
exit(0);
}
Сравнение различных систем межпроцессного взаимодействия
Заканчивая разговор о межпроцессном взаимодействии в UNIX, приведем сводную сравнительную таблицу рассмотренных систем.
|
Каналы |
FIFO |
Сообщения |
Разделяемая память |
Сокеты (домен UNIX) |
Пространство имен |
— |
Имя файла |
Ключ |
Ключ |
Имя файла |
Объект |
Системный канал |
Именованный канал |
Очередь сообщений |
Разделяемая область памяти |
Коммуникационный узел |
Создание объекта |
pipe() |
mknod() |
msgget() |
shmget() |
socket() |
Связывание |
pipe() |
open() |
msgget() |
shmat() |
bind() connect() |
Передача данных |
read() write() |
read() write() |
msgrcv() msgsnd() |
Непосредственный доступ memcpy() |
read() write() recv() send() recvfrom() sendto() |
Уничтожение |
close() |
close() unlink() |
msgctl() |
shmdt() |
close() unlink() |
Если говорить о производительности IPC, то наиболее быстрым способом передачи данных между неродственными процессами является разделяемая память. Разделяемая память является частью адресного пространства для каждого из взаимодействующих процессов, поэтому чтение и запись в эту область неотличимы, например, от чтения и записи в область собственных данных процесса. Однако при использовании разделяемой памяти необходимо обеспечить синхронизацию процессов. При использовании семафоров, необходимо иметь в виду следующие обстоятельства:
□ Применение семафоров может увеличить число процессов в очереди на выполнение, поскольку несколько процессов, ожидающих разрешающего сигнала семафора, будут одновременно разбужены и переведены в очередь на выполнение.
□ Применение семафоров увеличивает число переключений контекста, что, в свою очередь, увеличивает нагрузку на систему.
□ В то же время, использование семафоров является наиболее стандартным (POSIX.1b), хотя и неэффективным способом обеспечения синхронизации.
Очереди сообщений предназначены для обмена короткими (обычно менее 1 Кбайт) структурами данных. Если объем данных превышает эту величину, использование сообщений может значительно увеличить число системных вызовов и уменьшить производительность операционной системы.
Читать дальше