InicioLinuxProgramacion GNU/Linux: Pipes y FIFOS

Programacion GNU/Linux: Pipes y FIFOS

Linux12/9/2009
Ejemplo de utilizacion de pipes y fifos para la transmision de datos entre procesos.

Pipe,Problema 1: Un proceso central controla la informacion que 20 sensores le envian cada 15 segundos. Luego de registrar 10 temperaturas, las promedia (por cada sensor) y las muestra por pantalla. Al final de la ejecucion, el proceso central le envia la señal de terminacion a los sensores y muestra el promedio final de cada sensor.

FIFO, Problema 2: 2 clientes y un servidor se comunican mediante FIFOS. La comunicacion entre los clientes es fullduplex. El servidor recibe los datos del cliente 1 y se los envia al cliente 2 y viceversa.

Aclaracion: Doy por sentado que el que lee este post conoce temas de programacion en GNU/Linux como son el manejo de señales, la creacion de procesos hijos y el uso de algunas funciones y librerias basicas del lenjuage de programacion C.
Este tema esta dirijido a aquellas personas que cursen la materia Sistemas Operativos y la idea es que tengan este ejemplo para poder tener una idea del funcionamiento de estas formas de comunicacion entre procesos.

La explicacion teorica de cada uno de estos temas queda fuera del alcance de este post. La idea es tener una aproximacion practica del tema.

Tambien me gustaria mantener una retroalimentacion con los interesados sobre el tema y estoy dispuesto a escuchar otras ideas o alternativas de la utilizacion de estas estructuras o de cualquier otra relacionada a la programacion en GNU/Linux.

Dado que este es mi primer post, es posible que falten cosas o que no sea claro en lo que quiero trasmitir. Por eso estoy dispuesto a recibir criticas, consejos o sugerencias de las personas que lean el post.

Codigo del Problema 1:
//temperaturas.c
/*Para terminar el proceso principal, se le tiene que enviar desde
otra terminal la señal SIGUSR2(12) al pid del mismo*/
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
//Descriptor pipe y constantes para la escritura y lectura
int fd[2];
#define ESCRITURA 1
#define LECTURA 0
//Maximo sensores
#define SENSORES 20
//Tiempo de espera de cada sensor
#define ESPERA 15
//Cantidad de temperaturas que seran promediadas
#define PROMEDIAR 9
//Estructura sensores
struct hijo{
int pid;
int numero;
int maxima;
int minima;
int procesadas;
int suma;
int totalProcesadas;
int totalSuma;
}sensor[SENSORES];
//Bandera para los sensores
int seguir;
//Registra temperatura
void registrar (int numeroSenial, siginfo_t *infoSenial, void *contex) ;
//Termina registro de temperaturas y finaliza sensores
void terminar (int senial) ;

int main(void){
system("clear" );
int i;
//Buffer de escritura
int writebuffer;
pid_t pid_sensor, pid_central;
pid_central = getpid() ;
//Bandera en 1
seguir = 1;
//Crear pipe
pipe(fd);
//Sigaction para la señal SIGUSR1
struct sigaction registro;
sigemptyset(&registro.sa_mask) ;
registro.sa_flags = SA_SIGINFO | SA_RESTART;
registro.sa_sigaction = registrar;
if (sigaction(SIGUSR1,&registro,NULL)!=0){
printf("No se pudo asignar la funcion para el tratamiento de la señal SIGUSR1\n" );
exit(1) ;
}
//Crear sensores
for (i=0;i<SENSORES;i++){
if ((pid_sensor=fork())!=0){
sensor.pid = pid_sensor;
sensor.numero = i;
sensor.maxima = -500;
sensor.minima = 500;
sensor.procesadas = 0;
sensor.suma = 0;
sensor.totalSuma = 0;
sensor.totalProcesadas = 0;
usleep(150000);
}else{
//Regenero semilla de numeros aleatorios
srand((time(NULL)+i));
//Los sensores pueden capturar la señal SIGTERM
signal(SIGTERM,SIG_DFL);
//Cierro el lado de lectura del pipe
close(fd[LECTURA]);
while (seguir == 1){
//Sensor duerme el tiempo definido en ESPERA
sleep(ESPERA);
//Se le asigna un numero aleatorio entre -70 y 70
writebuffer = -70+(int)(((70+70+1.0)*rand())/(RAND_MAX+1.0));
//Le avisa al proceso central que le va a enviar una temperatura
kill(pid_central,SIGUSR1);
//Escribe la temperatura en el pipe
write(fd[ESCRITURA],&writebuffer,sizeof(writebuffer));
}
//Sensor espera señal
pause();
}
}
//Proceso principal captura señal SIGUSR2 y la trata la funcion terminar
signal(SIGUSR2,terminar);
//Cierro el lado de escritura del pipe
close(fd[ESCRITURA]);
printf("Iniciado registro de temperaturas\n" );
for( ;; );
return 0;
}
void registrar (int numeroSenial, siginfo_t *infoSenial, void *contex){
int i;
//Buffer de lectura
int readbuffer;
int promedio;
//Leo desde el pipe la temperatura
read(fd[LECTURA],&readbuffer,sizeof(readbuffer)) ;
//Busco a que sensor corresponde y la proceso
for(i=0;(i<SENSORES) && (sensor.pid!=infoSenial->si_pid); i++) ;
printf( "\n" );
printf("Lei la temperatura %d del sensor %d\n",readbuffer,i) ;
sensor.totalSuma+= readbuffer;
sensor.totalProcesadas++;
//Si es la minima
if(sensor.minima > readbuffer){
sensor.minima = readbuffer;
}
//Si es la maxima
if(sensor.maxima < readbuffer){
sensor.maxima = readbuffer;
}
printf("Temperatura minima: %d\n",sensor.minima) ;
printf("Temperatura maxima: %d\n",sensor.maxima) ;
//Si se registraron 10 temperaturas las promedio
if (sensor.procesadas<PROMEDIAR){
sensor.suma +=readbuffer;
sensor.procesadas++;
}else{
promedio = (int) sensor.suma/sensor.procesadas;
printf("Promedio de las ultimas %d temperaturas: %d\n",(PROMEDIAR+1),promedio) ;
sensor.suma =0;
sensor.procesadas=0;
}
return;
}
void terminar (int senial){
signal(SIGUSR2,terminar) ;
int i,promedioGeneral;
seguir = 0;
printf("\n" );
printf("Terminando sensores\n" );
printf("Sensor\t Estado\n" );
//Termino sensores
for (i=0;i<SENSORES;i++){
//Le envio la señal de terminacion a cada sensor
kill(sensor.pid,SIGTERM);
printf("%d\t Terminado\n",sensor.numero);
}
printf( "\n" );
printf( "Sensor\t Maxima\t Minima\t Promedio General\n" );
//Promedio general, maxima y minima de cada sensor
for (i=0;i<SENSORES;i++){
promedioGeneral = (int) sensor.totalSuma/sensor.totalProcesadas;
printf( "%d\t %d\t %d\t\t %d\n",sensor.numero,sensor.maxima,sensor.minima,promedioGeneral);
}
//Cierro el lado de escritura y lectura del pipe
close(fd[ESCRITURA]);
close(fd[LECTURA]);
exit(0);
return;
}

Codigos del Problema 2:
//servidor.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
//Rutas utilizadas para crear los FIFOS de cada cliente
#define CLIENTE1_TX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente1_tx"
#define CLIENTE1_RX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente1_rx"
#define CLIENTE2_TX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente2_tx"
#define CLIENTE2_RX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente2_rx"
//Tipo de acceso para los FIFOS
#define ACCESO 0666
//Variables que guardan los FIFOS
int cliente1_tx, cliente1_rx, cliente2_tx, cliente2_rx;
//Funcion que gestiona la señal SIGINT
void terminar(int senial);

int main(void){
//Buffer
char buffer1[PIPE_BUF], buffer2[PIPE_BUF];
//Creo los FIFOS
if( mkfifo(CLIENTE1_TX,ACCESO) == -1 ){
perror( "Error en mkfifo cliente1_tx" );
exit(1);
}
if(mkfifo(CLIENTE1_RX,ACCESO) == -1){
perror( "Error en mkfifo cliente1_rx" );
exit(1);
}
if(mkfifo(CLIENTE2_TX,ACCESO) == -1){
perror( "Error en mkfifo cliente2_tx" );
exit(1);
}
if(mkfifo(CLIENTE2_RX,ACCESO) == -1){
perror( "Error en mkfifo cliente2_rx" );
exit(1);
}
//Abrir FIFOS
if((cliente1_tx=open(CLIENTE1_TX,O_WRONLY))==-1){
perror( "Error en open cliente1_tx" );
exit(2);
}
if((cliente1_rx=open(CLIENTE1_RX,O_RDONLY))==-1){
perror( "Error en open cliente1_rx" );
exit(3);
}
if((cliente2_tx=open(CLIENTE2_TX,O_WRONLY))==-1){
perror( "Error en open cliente2_tx" );
exit(4);
}
if((cliente2_rx=open(CLIENTE2_RX,O_RDONLY))==-1){
perror( "Error en open cliente2_rx" );
exit(5);
}
printf( "Utilizar Ctrl-C para finalizar el proceso\n" );
printf( "Servidor: Esperando datos\n" );
//Configuro los FIFOS para que sean no bloqueantes
fcntl(cliente1_rx,F_SETFL,O_NONBLOCK);
fcntl(cliente2_rx,F_SETFL,O_NONBLOCK);
signal(SIGINT,terminar);

while (1) {
//Cliente 1
if(read(cliente1_rx,buffer1,sizeof(buffer1))>0){
if(buffer1[0]!='1'){
printf("Servidor: Leido del Cliente 1: %s\n",buffer1);
printf( "Servidor: Enviando datos al Cliente 2\n" );
write(cliente2_tx,buffer1,sizeof(buffer1));
}
}

//Cliente2
if(read(cliente2_rx,buffer2,sizeof(buffer2))> 0){
if(buffer2[0]!='1'){
printf( "Servidor: Leido del Cliente 2: %s\n",buffer2);
printf( "Servidor: Enviando datos al Cliente 1\n" );
write(cliente1_tx,buffer2,sizeof(buffer2));
}
}
}

return 0;
}
void terminar(int senial){
printf( "\nServidor: Terminado\n" );
close(cliente1_tx);
close(cliente1_rx);
close(cliente2_tx);
close(cliente2_rx);
unlink(CLIENTE1_TX);
unlink(CLIENTE1_RX);
unlink(CLIENTE2_TX);
unlink(CLIENTE2_RX);
exit(0);
}

//cliente1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#define CLIENTE1_RX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente1_tx"
#define CLIENTE1_TX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente1_rx"
pid_t pidHijo;
int cliente1_tx,cliente1_rx;
void terminar(int senial);

int main(void){
pid_t hijo;
char buffer1[PIPE_BUF], buffer2[PIPE_BUF];

if((cliente1_rx=open(CLIENTE1_RX,O_RDONLY))==-1){
perror( "Error en open cliente_rx" );
exit(2);
}
if((cliente1_tx=open(CLIENTE1_TX,O_WRONLY))==-1){
perror("Error en open cliente_tx" );
exit(2);
}
fcntl(cliente1_rx,F_SETFL,O_NONBLOCK);
signal(SIGINT,terminar);
if((hijo=fork())!=0){
while(1){
printf( "\nCliente 1: " );
fflush( stdout );
gets(buffer1);
write(cliente1_tx,buffer1,sizeof(buffer1));
}
}else{
signal(SIGINT,SIG_IGN);
signal(SIGTERM,SIG_DFL);
pidHijo = hijo;
while(1){
if(read(cliente1_rx,buffer2,sizeof(buffer2))> 0){
if(buffer2[0]!='1'){
fflush( stdout );
printf("\nCliente 2: %s\n",buffer2);
}
}
}
}
return 0;
}
void terminar(int senial){
signal(SIGINT,terminar);
printf( "\nCliente 1: Terminado\n" );
kill(pidHijo,SIGTERM);
close(cliente1_tx);
close(cliente1_rx);
exit(0);
}

//cliente2.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#define CLIENTE2_RX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente2_tx"
#define CLIENTE2_TX "/home/ubuntu/Escritorio/practico4/ejercicio4/cliente2_rx"
pid_t pidHijo;
int cliente2_tx,cliente2_rx;
void terminar(int senial);

int main(void){
pid_t hijo;
char buffer1[PIPE_BUF], buffer2[PIPE_BUF];

if((cliente2_rx=open(CLIENTE2_RX,O_RDONLY))==-1){
perror( "Error en open cliente_rx" );
exit(2);
}
if((cliente2_tx=open(CLIENTE2_TX,O_WRONLY))==-1){
perror( "Error en open cliente_tx" );
exit(2);
}
fcntl(cliente2_rx,F_SETFL,O_NONBLOCK);
signal(SIGINT,terminar);
if((hijo=fork())!=0){
while(1){
printf( "\nCliente 2: " );
fflush( stdout );
gets(buffer1);
write(cliente2_tx,buffer1,sizeof(buffer1));
}
}else{
signal(SIGINT,SIG_IGN);
signal(SIGTERM,SIG_DFL);
pidHijo = hijo;
while(1){
if(read(cliente2_rx,buffer2,sizeof(buffer2))> 0){
if(buffer2[0]!='1'){
fflush( stdout );
printf("\nCliente 1: %s\n",buffer2);
}
}
}
}
return 0;
}
void terminar(int senial){
signal(SIGINT,terminar);
printf( "\nCliente 2: Terminado\n" );
kill(pidHijo,SIGTERM);
close(cliente2_tx);
close(cliente2_rx);
exit(0);
}

Si bien el post es bastante basico creo que va a ser de mucha utilidad para cierta gente. Eso es todo por ahora y les mando un saludo. Espero sus comentarios.
Datos archivados del Taringa! original
0puntos
2,769visitas
0comentarios
Actividad nueva en Posteamelo
0puntos
3visitas
0comentarios
Dar puntos:

Dejá tu comentario

0/2000

Autor del Post

e
ezequielGR🇦🇷
Usuario
Puntos0
Posts1
Ver perfil →
PosteameloArchivo Histórico de Taringa! (2004-2017). Preservando la inteligencia colectiva de la internet hispanohablante.

CONTACTO

18 de Septiembre 455, Casilla 52

Chillán, Región de Ñuble, Chile

Solo correo postal

© 2026 Posteamelo.com. No afiliado con Taringa! ni sus sucesores.

Contenido preservado con fines históricos y culturales.