Как стать автором
Обновить
0

Межпроцессное взаимодействие и Unix Domain Socket

Время на прочтение 8 мин
Количество просмотров 4.2K
Недавно по работе пришлось решать достаточно интересную задачу.
Нужно было написать приложение — демон, которое записывает мультикаст поток в файл.
При этом необходимо было писать несколько мультикаст потоков параллельно…
Более того… нужно централизованно управлять этими демонами!

Немного теории

По сути само приложение по себе — достаточно простое… Но вот встает вопрос управления… Когда демон уже запущен — ему надо передавать команды… например сменить файл, в который пишется поток… или вообще прекратить запись. Встал вопрос — как управлять такими демонами…

Перелапатив несколько страниц гугла и начитавшись заумных статей было решено остановиться на варианте с Unix Domain Socket…

Архитектура проста… Приложению при запуске, помимо параметров «чего куда писать» передается его уникальный id, по которому генерируется имя управляющего сокета ( банально sock_[id] ). Все сокеты создаются в заранее оговоренной директории на сервере… пусть это будет /tmp/my_socks/.
Таким образом приложение-менеджер при запуске делает листинг этой директории и смотрит — какие процессы у него запущены… затем проводит «ping» этих процессов (через эти же сокеты) и проверяет — какие из них действительно живы… Мертвые сокеты (у которых процесс по каким-то причинам отсутствует ) — можно сразу же удалить…

Ну а после того как сокет открыт можно обмениваться любыми командами с конкретным процессом… получается вот такое двухстороннее межпроцессное взаимодействие.

Но это теория! Ниже немного практики…

Реализация

Приложение, записывающее поток было реализовано на gcc
Нужные нам инклуды и структуры

#include <sys/types.h><br/>#include <sys/socket.h><br/>#include <sys/un.h><br/>#include <netdb.h><br/>#include <arpa/inet.h><br/>#include <unistd.h><br/>#include <netinet/in.h><br/>#include <stdlib.h><br/>#include <stdio.h><br/>#include <string.h><br/>#include <fcntl.h><br/> <br/>  int ctrlsock, ns;<br/>  struct sockaddr_un saun;<br/> <br/>


Инициализируем сокет и начинаем его слушать:

void init_ctrl_socket() {<br/>   // Создаем сокет.. Семейство AF_UNIX указывает что это будет локальный unix-socket<br/>  if ( ( ctrlsock = socket(AF_UNIX, SOCK_STREAM,  0) ) <  0 ) {<br/>    savelog("ERROR: control socket creating error");<br/>    exit(1);<br/>  }<br/> <br/>  // Делаем сокет неблокирующим.. чтобы при чтении не ждать..<br/>  int flags = fcntl(ctrlsock, F_GETFL,  0);<br/>  if ( fcntl(ctrlsock, F_SETFL, flags | O_NONBLOCK) <  0 ) {<br/>    savelog("ERROR: don't set socket on nonblocket mode");<br/>    exit(1);<br/>  }<br/> <br/>   // Вот тут самое интересное.. <br/>   // биндим сокет. Передаем ему - путь до сокета..<br/> <br/>  saun.sun_family = AF_UNIX;<br/>  strcpy(saun.sun_path, "/tmp/my_socks/sock_01"); // вот тут путь до сокета<br/>  int len = sizeof(saun.sun_family) + strlen(saun.sun_path);<br/> <br/>  if (bind(ctrlsock, (struct sockaddr *)&saun, len) <  0) {<br/>        savelog("ERROR: control socket binding error");<br/>        exit(1);<br/>  }<br/> <br/>  if (listen(ctrlsock, 5) <  0) {<br/>        savelog("ERROR: control socket listening error");<br/>        exit(1);<br/>  }<br/>}<br/> <br/> <br/>


Прием команд из сокета:

void check_ext_command() {<br/>      int fromlen = sizeof(struct sockaddr);<br/>      if ( (ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen) ) >  0 ) {<br/>            char lbuf[255];<br/>            int ilen;<br/>            ilen = recv( ns, &lbuf, 255,  0 );<br/>            lbuf[ilen]='\0';<br/>            do_remote_command( lbuf ); // Тут вызывается функция обработки команды..<br/>            close(ns);<br/>      } <br/>}<br/> <br/>


Запись в сокет производиться как и обычно:

char msg = "my message";<br/>send( ns, msg, strlen(msg),  0);<br/> <br/>


Менеджер для процессов

Менеджер для процессов был написан на php. Для того чтобы было удобно управлять ими через браузер…
Вот пример опроса существующих процессов

class reccontrol {<br/> <br/>    var $socket_path = '/tmp/my_socks/'; // Путь где лежат сокеты приложений<br/>    var $socket_prefix = 'sock_'; //  Префикс сокеты (для эстетической красоты :))<br/>    var $list = array();<br/> <br/>    function getList() {<br/>        $this->writers_info = array();<br/>        $arr = scandir( $this->socket_path);<br/>        unset($arr[  0]); // .<br/>        unset($arr[1]); // ..<br/>        foreach( $arr as $k =>$s_name ) {<br/>               if ( !$this->ping( $s_name ) ) { <br/>                      // Если не ответил на пинг - значит процесс умер или повис<br/>                      @unlink( $this->socket_path . $s_name ); <br/>                      unset( $arr[$k] ); <br/>               }<br/>        }<br/>        $this->list = $arr;<br/> <br/>    }<br/> <br/>    // Реализация "опроса процессов"<br/>    function ping( $s_name ) {<br/>        $socket_name = $this->socket_path.$s_name; // полный путь<br/>        $sock = $this->getSock( $socket_name ); // Вынес в отдельную функцию для удобства<br/> <br/>        if ( !$sock ) return false; // не отвечает - значит пинг не прошел<br/> <br/>        $buf = "ping";<br/>        if ( @socket_send($sock, $buf, strlen($buf),  0) == false ) {<br/>                return false; // не записать - значит пинг не прошел<br/>        }<br/> <br/>        $buf = '';<br/>        @socket_recv($sock, $buf, 1024,  0 );<br/>        if ($buf) { <br/>             // в $buf - то, что вернул нам процесс.. какую-то полезную инфу о себе<br/>             addlog("Процесс " . $s_name . " ответил: " . $buf); <br/>        }<br/> <br/>        socket_close($sock); <br/>        return true; // Сокет ответил - всё ок!<br/>    }<br/> <br/>   // Непосредственно создание unix сокета.. даже проще, чем в Си :)<br/>    function getSock( $socket_name ) {<br/>        // Указываем, что семейство AF_UNIX<br/>        $socket = @socket_create(AF_UNIX, SOCK_STREAM,  0); <br/>        // в $socket_name у нас лежит что-то типа /tmp/my_socks/sock_1 - т.е. путь до сокета<br/>        if ( @socket_connect( $socket, $socket_name) == false ) { <br/> <br/>            $err = socket_last_error();<br/>            if ( $err ) {<br/>                return false; // не удалось открыть сокет :(<br/>            }<br/>        } else {<br/>            return $socket; // всё ок - возвращаем дескриптов сокета<br/>        }<br/>    }<br/> <br/>} <br/>


Вот такое вот получается взаимодействие…
Здесь опубликованы только небольшие части кода — выполняющие основной функционал… Целиком просто всё это выглядит весьма громоздко и конкретная программа бесполезна обычному обывателю… Весь смысле в идеи управления…
Можно зайдя на web страничку получить информацию с нескольких процессов (она позвращается при пинге) и дать определенным процессам определенные команды…
Теги:
Хабы:
+9
Комментарии 8
Комментарии Комментарии 8

Публикации

Информация

Сайт
www.angels-it.ru
Дата регистрации
Дата основания
Численность
2–10 человек
Местоположение
Россия

Истории