ezequielGR
Usuario (Argentina)
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; //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(®istro.sa_mask) ; registro.sa_flags = SA_SIGINFO | SA_RESTART; registro.sa_sigaction = registrar; if (sigaction(SIGUSR1,®istro,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); 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,&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); 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,&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); close(fd); 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.