IPC: Comunicación entre procesos en *nix
IPC, o Inter Process Communication, comprende una serie de mecanismos diferenciados que nos permiten, desde un proceso enviar un dato a otro, y de esta forma, comunicarlos.
Parece complejo implementar este tipo de estructuras en nuestros códigos fuente de C, pero en realidad no lo es tanto, y para alguien que ha estado trabajando en sistemas Unix/Linux, lo verá de una manera mucho más tangible, puesto que el mismo sistema operativo lo utiliza todo el tiempo, y nosotros solemos implícitamente utilizarlos en nuestras líneas de comandos.
Envío de señales
Algunos mecanismos son simples, como el envío de una señal de un proceso a otro, que el proceso receptor capturará y trabajará de un modo determinado, dependiendo del código de señal. Esto puede programarse e implementarse en un programa C de múltiples procesos, y permitirle a estos procesos enviarse señales que bifurquen sus ejecuciones.
En el sistema operativo, por ejemplo, cuando ejecutamos un proceso y lo cancelamos con la combinación de teclas «ctrl+c«, o cuando usamos los comandos kill o killall, estamos siempre enviando algun tipo de señal a algún proceso. El intérprete de comandos solo nos facilita algún tipo de facilidad.
[die@debian ~]$ sleep 10 ^C [die@debian ~]$
La ventaja de poder programar esto, es que en nuestros procesos podemos lograr que las reacciones a la recepción de ciertas señales varíe de sus implementaciones estándar.
Pipes
Otros mecanismos no menos útiles son los pipes, o tuberías. El símbolo «|» que utilizamos comúnmente para comunicar la salida de un proceso con la entrada de otro, logrando una salida enriquecida, es un pipe que se genera al vuelo durante la ejecución de los comandos, y permite procesar la salida de un comando mediante otro/s, por ejemplo:
#### mostramos tres lineas por pantalla:
[die@debian ~]$ echo -e «hola mundonesta es la segunda linea\n… y una tercera»
hola mundo esta es la segunda linea … y una tercera
#### filtramos la segunda línea usando grep: [die@debian ~]$ echo -e "hola mundo\nesta es la segunda linea\n... y una tercera" |grep segunda esta es la segunda linea ### filtramos la cadena "la" de la segunda línea: [die@debian ~]$ echo -e "hola mundo\nesta es la segunda linea\n... y una tercera" |grep segunda | cut -d' ' -f3 la
Como se ve, el uso de pipes es muy poderoso para intérpretes de comandos y scripting.
FIFOS o Named Pipes
Estos pipes pueden programarse en C y trabajarse de una manera muy flexible, incluso escribiendo pipes en disco, que se verán como archivos, pero que servirán de punto de contacto entre procesos totalmente independientes, para intercambio de información. Este tipo de pipe en sistema de archivos se lo conoce como FIFO, o «named pipe», veamos un ejemplo:
[die@debian ~]$ ls -l /var/run/acpi_fakekey p-w------- 1 root root 0 Feb 19 10:35 /var/run/acpi_fakekey [die@debian ~]$ file /var/run/acpi_fakekey /var/run/acpi_fakekey: fifo (named pipe)
Sockets UNIX
Otra de las herramientas es el socket. El socket automáticamente nos trae a la cabeza conexiones de red. Sin embargo, esto no siempre es así. Existen en sistemas *nix dos grandes tipos de sockets. Los sockets UNIX son similares a los fifos, archivos en disco que permiten la comunicación entre procesos locales, por ejemplo:
[die@debian ~]$ ls -l /var/run/cups/cups.sock srwxrwxrwx 1 root root 0 Feb 19 10:35 /var/run/cups/cups.sock [die@debian ~]$ file /var/run/cups/cups.sock /var/run/cups/cups.sock: socket
Podemos ver la lista de sockets Unix de esta forma:
Sockets INET
Otro tipo de socket es el socket INET, que efectivamente, permite conectar procesos en red, o localmente, utilizando redes TCP/IP. Estos sockets no tienen una representación en el sistema de archivos, pero sí pueden analizarse y ver las conexiones que nuestros procesos están efectuando contra otros procesos.
Veamos los sockets que yo tengo en este momento abiertos entre mis procesos locales y procesos remotos, ubicados por ip:
Estos dos tipos de sockets, de más está decir, también se pueden programar y utilizar su gran potencia para crear aplicaciones más complejas y eficientes.
IPC: Semáforos
Otro de los mecanismos utilizables desde código son los semáforos, que como su nombre lo dice, permiten o deniegan el acceso a ciertos recursos, a un proceso. Podríamos, por ejemplo, tener varios procesos concurrentes tratando de modificar un archivo, y para evitar que las escrituras se solapen, podríamos implementar semáforos, que le den el acceso a un proceso, y dejen en espera stand-by al resto, hasta que el recurso se desocupe.
Si alguna aplicación está utilizando un semáforo, podremos verla identificada de esta forma:
[die@debian ~]$ ipcs -s ------ Semaphore Arrays -------- key semid owner perms nsems
IPC: Colas de mensajes
Las colas de mensajes son otro mecanismo de IPC que permite a dos procesos, incluso procesos no relacionados, a enviarse mensajes y datos enter si.
Es un mecanismo similar al de los named-pipes, pero la cola de mensaje permanece en la memoria del sistema operativo, y permite a un emisor escribir mensajes en la cola, y a un receptor recuperarlos y «consumirlos» desde la misma.
IPC: Memoria compartida
Por último, otro de los mecanismos que podemos analizar, son los segmentos de memoria compartida. Cada proceso en Linux mantiene un rango de direcciones de memoria virtual para poder trabajar, dividido en diversos segmentos, que a su vez se estructuran en páginas de igual tamaño.
Pero lo más importante es que un proceso no puede modificar información del mapa de memoria de otro proceso, por lo que no habría forma de intercambiar datos entre procesos utilizando memoria.
Sin embargo, un proceso sí puede definir segmentos de memoria compartidos que le permitan a otro proceso acceder a sus datos, y modificarlos, en el caso de que sea necesario.
Los segmentos de memoria compartida son muy utilizados en un sistema, y podremos listarlos con:
Conclusiones
Sobra decir que en la flexibilidad de un código fuente escrito en C podemos combinar varios de estos mecanismos para lograr nuestros objetivos.
Por ejemplo, podríamos, por ejemplo, mapear un archivo en memoria para que un proceso lea los datos y los publique en un segmento de memoria compartida, que será accedido por otro proceso, y que leerá los datos y los enviará a otro equipo en la red mediante un socket INET.
Estos son algunos de los mecanismos principales de comunicación de procesos en Linux, de conocerlos a saber utilizarlos y programarlos hay un paso un poco más largo, pero de por más interesante… tengamos en cuenta que hablando de C y sistemas *nix, las posibilidades son casi infinitas 🙂