COMUNICACIÓN ENTRE PROCESOS En un sistema multitarea o multiproceso es muchas veces necesario que existan mecanismos de comunicación entre los distintos procesos del sistema o entre procesos / aplicaciones entre máquinas distintas. Muchas aplicaciones actuales se realizan siguiendo un modelo cliente y servidor, lo que permite distribuir la carga de cada programa en distintas máquinas, aumenta la seguridad y flexibilidad. Parte cliente : Capturar los las datos, los muestra, solicitar las consultas, mantener el interfaz de usuario. Parte Servidor : Almacena y valida los datos, realiza los cálculos complejos, contestar las respuestas Esquema: SERVIDOR Inicializar Abrir Canal de peticiones MIENTRA(1) Leer(Petición) ElaborarRespuesta(Petición, resultado) Enviar(resultado) FIN-MIENTRAS CLIENTE Inicializar Conectar con el Servidor EnviarPetición (datos petición); EsperarRespuesta (datos respuesta); ProcesarRespuesta ( datos respuesta); Los servidores pueden suele ser interactivos o concurrentes -Interactivos: Realizan ellos mismo el tratamiento de la petición,-> Sólo pueden procesar una petición cada vez -Concurrentes: Crean nuevos procesos o mantienen activos una serie de ellos para tratar cada nueva petición -> Pueden procesar varias peticiones cada vez Cuando una aplicación está formada por muchos procesos que comparten una gran cantidad de datos siendo preciso el menor tiempo de respuesta posible, el método ideal es utilizar múltiples hilos en vez de proceso normales. Sin embargo esto tiene el inconveniente de obligar a que toda la aplicación se ejecute sobre una misma máquina lo que reduce la flexibilidad. Habitualmente se utilizan métodos mixtos la aplicación cliente - servidor se realiza en base a varios procesos cada uno de ellos con múltiples hilos. MECANISMOS DE COMUNICACIÓN Internos (Entre procesos dentro de una misma máquina ) Básicos •Señales ( Informan de sucesos pero no sirven para envían o reciben datos adicionales) •Ficheros con bloqueos ( Relativamente lento -> acceso a disco ) ( Pseudo- Bases de Datos ) •Tuberías : Fifo internas (pipe) y fifos externas con nombre ( Memoria RAM, más rápida, capacidad limitada 4 – 8 kb ) Mecanismos IPC de UNIX System V •Semáforos ( Mecanísmo de sincronización ) •Colas de mensajes ( Intercambio ordenado de cantidades discretas de datos ) •Memoria compartida ( Acceso compartido a un mismo espacio de memoria) Externos (Entre proceso de distintas máquinas conectadas mediante una red ) Comunicación basada en sockets AF_UNIX ( Similar a la fifos con nombre pero bidireccionales) AF_INET ( Mediante el uso del protocolo TCP/IP ) -> TCP o UDP TUBERIAS O PIPES. FIFOS INTERNOS Es el método más sencillo y antiguo de comunicación entre dos procesos donde la salida de un programa es la entrada del otro (pipeline). Una Tuberia o pipe, es una estructura de datos interna que ofrece el kernet, que pueden contener un conjunto limitado de datos ( 4 a 8 K), a la que se accede mediante operaciones de lectura y escritura sobre dos descriptores, uno de abierto para lectura y otro para escritura. Se implementa un modelo productor Æ consumidor, más que cliente - servidor. Permite una comunicación Simplex (unidireccional.) Ejemplos: $who | sort $ps -ef | fgrep a01 | wc -l ¿Que es lo que ocurre cuando ejecutamos la orden who | sort? •Se crea un pipe, tubería interna. •Se redirecciona la salida estándar del proceso who al ( descriptor nº 1 ) al pipe •Se redirecciona la entrada estándar del proceso sort (descriptor nº 0 ) al pipe •Y se ejecutan cada programa independiente Proceso who Proceso sort Tubería interna Salida estándar Entrada estándar PREVIO: Concepto de redirección y llamada dup int dup ( descriptor ) Duplicar un descriptor abierto: Abre un nuevo descriptor que señala al mismo fichero o i_nodo que el indicado Ej.fd = open(“datos.dat”,O_RDONLY); nfd = dup(fd); write(nfd, datos, nbytes ); // Tanto el descritor fd como nfd están señalando al mismo fichero. Ej.- Redirección Numeración de los descriptores: 0 - stdin 1 - stdout 2 - stderr Cada vez que se abre un descriptor se asigna el valor más bajo disponible. Ejemplo sencillo de redirección: fclose(stdout); pf = fopen(“Salida.txt”,”w”); printf(“ %s”,mensaje); fprintf(pf,”%s”,mensaje); // Escriben sobre el mismo fichero system(“who”); /* La salida estándar (stdout) pasaría a ser el fichero Salida.txt por lo tanto el comando who al escribir en la sálida estándar escribirá realmente sobre el fichero Salida.txt */ CREACIÓN DE UNA TUBERÍA int pipe(int descf[2]); Parámetro una tabla con dos enteros. descf[0] Está abierto para lectura descf[1] Está abierto para escritura DESCRIPCIÓN pipe crea un par de descriptores de ficheros, que apuntan a un inodo de una tubería, La posición. descf[0] es para lectura, descf[1] es para escritura. Cada proceso suele cerrar descriptor que no vaya a utilizar antes de leer o escribir en el pipe. Comportamiento de una tuberia (pipe): •Comunicación Simplex. En una dirección. •Tamaño de 4.096 . Si esta lleno el proceso escritor se espera, si está vacía el proceso lector se espera •Si se ha cerrado el extremo de escritura, el lector puede continuar leyendo mientras haya datos hasta, la función read devuelve 0 byte indicando que está vacío. •Si se ha cerrado el extremo de lectura, al intentar escribir fallará generándose la señal SIGPIPE (Tubería Rota) Ejemplos en la web: 1.- Programar el comando ps -ef | sort 2.- Lector que envía al comando sort 3.- Lector y escritor inverso (Misma pantalla ) La forma fácil: la función de librería POPEN FILE *popen(const char *orden, const char *tipo); int pclose(FILE *flujo); DESCRIPCIÓN La función popen() inicia un proceso creando una tubería, llamando a fork, para crear el proceso y ejecutando el intérprete de comandos (shell). Puesto que una tubería es unidireccional por definición, el argumento tipo sólo puede especificar lectura o escritura, pero no ambos; el flujo resultante es respectivamente de lectura o escritura exclusiva. Ejemplos en la web: 1. Lector que envía al comando sort popen 2. Muestra el contenido de una tabla en orden. TUBERIAS CON NOMBRE (FIFO) Inconveniente de las tuberías internas o pipe: Los procesos deben ser parientes => mismo usuario, arrancarse casi a la vez, Un nuevo proceso arrancado por un usuario no puede comunicarse con otro arrancado anteriormente. Características de la FIFO ( Tuberías externas o con nombre ) Una tubería con nombre funciona como un pipe normal, pero tiene algunas diferencias notables: •Las tuberías con nombre existen en el sistema de archivos como un archivo de dispositivo especial. Con su propietario, grupo y permisos correspondientes (prw-rw-r--) •Los procesos de diferentes padres pueden compartir datos mediante una tubería con nombre, si poseen los permisos necesarios. •Cuando se han realizados todas las operaciones de E/S la tubería con nombre no desaparecen sino que permanece en el sistema de archivos para un uso posterior, aunque no almacena datos si no hay ningún proceso con la tubería abierta. Creación de una FIFO: Por comando : mkfifo <nombre> prw-r--r-- P indica pipe. Por programa int mknod(nombre, S_IFIFO | 0666, 0); El valor 0666 corresponde con la mascara de permisos: rw-rw-rwUna FIFO se comporta como un fichero normal, pero sólo se puede abrir para leer o escribir, no se puede añadir y ni podemos posicionarnos. Normalmente, la apertura de una FIFO se realiza de forma sincronizada. En otras palabras, si se abre el FIFO para lectura, el proceso se quedará "bloqueado" hasta que cualquier otro proceso lo abra para escritura. Este comportamiento funciona al revés también. Si esta propiedad no nos interesa, se puede usar la opción O_ NONBLOCK o O_NDELAY en la llamada a open () para desactivar la acción de bloqueo por omisión. En este caso la llamada nos devolverá –1 si no hay nadie al otro lado. Comportamiento de una tubería con nombre (FIFO) • Las tuberías con nombre deberán tener como mínimo un lector y un escritor. • Si un proceso trata de escribir en una tubería que no tiene lector, el núcleo enviará la señal SIGPIPE que por omisión provoca la terminación del proceso. • Si un proceso intenta leer de una tubería que no tiene escritor, el S.O. Devuelve cero bytes en la llamada read indicando fin de fichero. • Estos comportamientos se pueden modificar abriendo el FIPO de entrada y salida • La tubería con nombre al igual que las pipes sólo permiten la comunicación unidireccional Ej.$ mkfifo canal $ cat canal & Probar desde otro terminal $ ls -l > canal Ejemplos de un Modelo productor- consumidor: Un proceso que envía y otro proceso que recibe: sobre una misma pipe llamada canal 1.- Abriendo y cerrando el pipe por cada mensaje: enviarfifo y recibirfifo 2.- Abriendo y cerrando al final: enviarfifo2 y recibirfifo2 Proceso leerfifo Proceso enviarfifo Fifo canal Ejemplo del Modelo cliente – servidor: Se utilizan dos fifos para permitir la comunicación en ambos direcciones. Una fifo para peticiones y y otra para respuestas Proceso Cliente Fifo frespuestas Proceso Servidor Fifo fpeticiones 3.- Ejemplo de cliente y servidor utilizando dos FIFO fpeticiones y frespuestas 4.- Servidor Matemático basado en el ejemplo anterior. 5.- Servidor con Múltiples clientes -> FIFO de repuesta privada, la dirección de respuesta se indica en el propio mensaje de petición. La fifo de respuesta se construye al partir del PID del proceso cliente. Proceso Cliente Pid=9283 Proceso Cliente Frespuestas9283 frespuestas3440 Pid=3440 Fifo fpeticiones Proceso Servidor