📜 ⬆️ ⬇️

Interprocess communication and Unix Domain Socket

Recently, the work had to solve a rather interesting task.
It was necessary to write an application - a daemon that writes a multicast stream to a file.
It was necessary to write several multicast streams in parallel ...
Moreover ... you need to centrally manage these demons!

A bit of theory

In essence, the application itself is quite simple ... But the control question arises ... When the demon is already running, it needs to send commands ... for example, change the file to which the stream is written ... or stop recording altogether. There was a question - how to manage such demons ...

Having overlapped several Google pages and having read abstruse articles, it was decided to dwell on the version with the Unix Domain Socket ...

The architecture is simple ... The application at launch, in addition to the “where to write” parameters, is transmitted its unique id, which generates the name of the controlling socket (trite sock_ [id]). All sockets are created in a predefined directory on the server ... let it be / tmp / my_socks /.
Thus, the application manager, when launched, makes a listing of this directory and looks at which processes it has started ... then pings these processes (through the same sockets) and checks which of them are really alive ... Dead sockets (which have reasons for missing) - you can immediately delete ...
')
Well, after the socket is open, you can exchange any commands with a specific process ... you get this two-way interprocess communication.

But this is a theory! Below is a little practice ...

Implementation

The application recording the stream was implemented on gcc
Inclusion and structure we need

#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/>


Initialize the socket and start listening to it:

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/>


Receiving commands from the socket:

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/>


Writing to the socket is done as usual:

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


Process Manager

The process manager was written in php. In order to be convenient to manage them through a browser ...
Here is an example of polling existing processes.

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/>


Here is the interaction ...
Only small parts of the code are published here - performing the basic functionality ... All in all, all this looks quite cumbersome and a specific program is useless to the average man in the street ... The whole sense of management ideas ...
You can go to the web page to get information from several processes (it comes to mind when pinging) and give certain processes to certain processes ...

Source: https://habr.com/ru/post/97847/


All Articles