Linux межпроцессное взаимодействие сокет

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

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

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

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

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

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

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

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

Реализация

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

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

void init_ctrl_socket() // Создаем сокет.. Семейство AF_UNIX указывает что это будет локальный unix-socket
if ( ( ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0 ) ) < 0 ) savelog( "ERROR: control socket creating error" );
exit( 1 );
>

// Делаем сокет неблокирующим.. чтобы при чтении не ждать..
int flags = fcntl(ctrlsock, F_GETFL, 0 );
if ( fcntl(ctrlsock, F_SETFL, flags | O_NONBLOCK) < 0 ) savelog( "ERROR: don't set socket on nonblocket mode" );
exit( 1 );
>

// Вот тут самое интересное..
// биндим сокет. Передаем ему — путь до сокета..

saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, «/tmp/my_socks/sock_01» ); // вот тут путь до сокета
int len = sizeof (saun.sun_family) + strlen(saun.sun_path);

if (bind(ctrlsock, ( struct sockaddr *)&saun, len) < 0 ) savelog( "ERROR: control socket binding error" );
exit( 1 );
>

if (listen(ctrlsock, 5 ) < 0 ) savelog( "ERROR: control socket listening error" );
exit( 1 );
>
>

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

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

Читайте также:  Вывод консоли файл linux
Менеджер для процессов

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

class reccontrol
var $socket_path = ‘/tmp/my_socks/’ ; // Путь где лежат сокеты приложений
var $socket_prefix = ‘sock_’ ; // Префикс сокеты (для эстетической красоты :))
var $list = array ();

function getList() $this ->writers_info = array ();
$arr = scandir( $this ->socket_path);
unset ( $arr [ 0 ]); // .
unset ( $arr [ 1 ]); // ..
foreach ( $arr as $k => $s_name ) if ( ! $this ->ping( $s_name ) ) <
// Если не ответил на пинг — значит процесс умер или повис
@unlink( $this ->socket_path . $s_name );
unset ( $arr [ $k ] );
>
>
$this -> list = $arr ;

>

// Реализация «опроса процессов»
function ping( $s_name ) $socket_name = $this ->socket_path. $s_name ; // полный путь
$sock = $this ->getSock( $socket_name ); // Вынес в отдельную функцию для удобства

if ( ! $sock ) return false ; // не отвечает — значит пинг не прошел

$buf = «ping» ;
if ( @socket_send( $sock , $buf , strlen( $buf ), 0 ) == false ) return false ; // не записать — значит пинг не прошел
>

$buf = » ;
@socket_recv( $sock , $buf , 1024 , 0 );
if ( $buf ) <
// в $buf — то, что вернул нам процесс.. какую-то полезную инфу о себе
addlog( «Процесс » . $s_name . » ответил: » . $buf );
>

socket_close( $sock );
return true ; // Сокет ответил — всё ок!
>

// Непосредственно создание unix сокета.. даже проще, чем в Си 🙂
function getSock( $socket_name ) // Указываем, что семейство AF_UNIX
$socket = @socket_create(AF_UNIX, SOCK_STREAM, 0 );
// в $socket_name у нас лежит что-то типа /tmp/my_socks/sock_1 — т.е. путь до сокета
if ( @socket_connect( $socket , $socket_name ) == false ) < $err = socket_last_error();
if ( $err ) return false ; // не удалось открыть сокет 🙁
>
> else return $socket ; // всё ок — возвращаем дескриптов сокета
>
>

>

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

Читайте также:  Запустить jupiter notebook linux

Источник

Оцените статью
Adblock
detector