Я хотел бы установить соединение IPC между несколькими процессами на Linux. Я никогда не использовал сокеты UNIX прежде, и таким образом я не знаю, является ли это корректным подходом к этой проблеме.
Один процесс получает данные (восстановленный после форматирования, двоичный файл) и должен распределить эти данные через локальный сокет AF_UNIX с помощью датаграммного протокола (т.е. подобный UDP с AF_INET). Данные, отправленные с этого процесса на локальный сокет Unix, должны быть получены несколькими клиентами, слушающими на том же сокете. Количество получателей может варьироваться.
Для достижения этого, следующий код используется, чтобы создать сокет и отправить данные в него (серверный процесс):
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
// buf contains the data, buflen contains the number of bytes
int bytes = write(socket, buf, buflen);
...
close(socket);
unlink(ipcFile.sun_path);
Эти возвраты записи-1 с errno, сообщающим о ENOTCONN ("Транспортная конечная точка не соединен"). Я предполагаю, что это вызвано тем, что никакой процесс получения в настоящее время не слушает этот локальный сокет, корректный?
Затем я пытался создать клиент, который соединяется с этим сокетом.
struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());
int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
char buf[1024];
int bytes = read(socket, buf, sizeof(buf));
...
close(socket);
Здесь, связывать сбои ("Адрес, уже используемый"). Так, я должен установить некоторые опции сокета, или это обычно - неправильный подход?
Заранее спасибо за любые комментарии / решения!
Вам следует изучить многоадресную IP-рассылку, а не что-нибудь в Unix-домене. Сейчас вы просто пытаетесь писать в никуда. И если вы подключитесь к одному клиенту, вы будете писать только этому клиенту.
Это работает не так, как вы думаете.
Ближайшая причина вашей ошибки заключается в том, что write ()
не знает, куда вы хотите отправить данные на . bind ()
устанавливает имя вашей стороны сокета, т.е. где данные поступают из . Чтобы установить конечную сторону сокета, вы можете использовать connect ()
; или вы можете использовать sendto ()
вместо write ()
.
Другая ошибка («Адрес уже используется») связана с тем, что только один процесс может привязать ()
к адресу.
Чтобы учесть это, вам нужно будет изменить свой подход. Вашему серверу необходимо будет прослушивать хорошо известный адрес, установленный с помощью bind ()
. Вашим клиентам нужно будет отправить сообщение на сервер по этому адресу, чтобы зарегистрировать свою заинтересованность в получении дейтаграмм. Сервер будет получать сообщения регистрации от клиентов, используя recvfrom ()
, и записывать адрес, используемый каждым клиентом. Когда он хочет отправить сообщение, он должен будет перебрать всех клиентов, о которых он знает, используя sendto ()
для отправки сообщения каждому из них по очереди.
В качестве альтернативы вы можете использовать локальную многоадресную рассылку IP вместо сокетов домена UNIX (сокеты домена UNIX не поддерживают многоадресную рассылку).
Не было бы проще использовать разделяемую память или именованные каналы? Сокет - это соединение между двумя процессами (на одной или другой машине). Это не метод массовой коммуникации.
Если вы хотите передать что-то нескольким клиентам, вы создаете сервер, который ждет соединений, а затем все клиенты могут подключиться, и он передает им информацию. Вы можете принять одновременные соединения, сделав программу многопоточной или разветвив процессы. Сервер устанавливает несколько соединений на основе сокетов с несколькими клиентами, вместо того, чтобы иметь один сокет, к которому подключаются несколько клиентов.