informatica:sol:laboratorio16:esercitazionia:fifoexample
Esempio di programma client/server che utilizza pipe con nome (FIFO)
Client e server comunicano con una pipe FIFO. In particolare il server riceve i comandi da eseguire su una FIFO “pubblica” e restituisce le risposte su una FIFO privata del client il cui nome è stato inviato insieme alla richiesta. Il processo server forka un processo per eseguire il comando richiesto dal client redirigendo lo standard output per ottenere il risultato.
msg.h
#if !defined(MSG_H)
#define MSG_H
#include <linux/limits.h> /* Linux specific definisce PIPE_BUF */
#define F_SIZE 256 /* size massima del nome della FIFO del client */
#define B_SIZE (PIPE_BUF-F_SIZE) /* size massima dei dati scambiati in modo atomico */
#define SYSCALL(r,c,e) \
if((r=c)==-1) { perror(e);exit(errno); }
// FIFO pubblica per inviare le richieste al server
const char *PUBLIC = "/tmp/PUBLIC";
/*
* In un singolo messaggio vogliamo inviare sia il comando da eseguire
* che il nome della fifo su cui vogliamo ottenere il risultato.
*/
struct message {
char fifo_name[F_SIZE];
char cmd_line[B_SIZE];
};
#endif /* MSG_H */
client.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "msg.h"
// nome della fifo privata
char fifo_name[F_SIZE];
void cleanup() {
int n;
SYSCALL(n, unlink(fifo_name), "cleanup: unlink private fifo");
}
int main() {
static char buffer[PIPE_BUF];
struct message msg;
int publicfifo, privatefifo, n;
// fifo privata per ricevere le risposte dal server
snprintf(fifo_name, F_SIZE, "/tmp/fifo%d", getpid());
SYSCALL(n, mkfifo(fifo_name, 0666), "mkfifo");
// qualora qualcosa vada storto
if (atexit(cleanup) != 0) {
fprintf(stderr, "ERRORE in atexit\n");
exit(EXIT_FAILURE);
}
// apro la fifo pubblica in sola scrittura
SYSCALL(publicfifo, open(PUBLIC,O_WRONLY), "open public fifo");
while(1) {
SYSCALL(n,write(1, "\n cmd>", 6), "write 1");
// resetto il messaggio
memset(msg.fifo_name, 0x0, F_SIZE);
memset(msg.cmd_line, 0x0, B_SIZE);
// leggo il comando da inviare al server
SYSCALL(n,read(0, msg.cmd_line, B_SIZE), "read 0");
// devo uscire ?
if(strncmp("quit", msg.cmd_line, n-1) == 0) break;
strncpy(msg.fifo_name,fifo_name, strlen(fifo_name)+1);
// mando la richiesta al server
SYSCALL(n, write(publicfifo, &msg, sizeof(msg)), "write public fifo");
// opro la fifo privata in sola lettura aspettando che il server la apra in scrittura
SYSCALL(privatefifo, open(msg.fifo_name, O_RDONLY), "open private fifo");
do {
memset(buffer, 0x0, PIPE_BUF);
SYSCALL(n ,read(privatefifo, buffer, PIPE_BUF), "read private fifo");
fprintf(stdout, "%s", buffer);
} while(n>0);
SYSCALL(n, close(privatefifo), "close private fifo");
}
SYSCALL(n, close(publicfifo), "close public fifo");
return 0;
}
server.c
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "msg.h"
#define MAXARGS 100 // massimo numero di argomenti di un comando
// costruisce un vettore di argomenti da una stringa
void buildargs(char *line, char * args[]) {
int i = 0;
args[i++] = strtok(line," \n");
do {
args[i] = strtok(NULL," \n");
} while(args[i++]!=NULL);
}
int main() {
struct message msg;
static char buffer[PIPE_BUF];
/*creating the PUBLIC fifo*/
if ((mkfifo(PUBLIC, 0666) == -1) && errno!=EEXIST) {
perror("mkfifo public fifo");
exit(errno);
}
int publicfifo;
// apertura in sola lettura per ricevere i comandi dai clients, aspetto che
// almeno uno dei client apra la fifo in scrittura
SYSCALL(publicfifo, open(PUBLIC, O_RDONLY), "open public fifo (read)");
// apro la fifo in scrittura per evitare di ricevere EOF sulla fifo pubblica
// che rimane sempre aperta
int notused;
SYSCALL(notused, open(PUBLIC, O_WRONLY|O_NONBLOCK), "open public fifo (write)");
while(1) {
int n, done;
SYSCALL(n, read(publicfifo, &msg, sizeof(msg)), "read public fifo");
if (n == 0) break; // ho letto EOF
n=0, done=0;
do {
int privatefifo;
// attendo che il client si connetta riprovando un po' di volte
if ((privatefifo = open(msg.fifo_name, O_WRONLY|O_NONBLOCK)) == -1) {
sleep(2);
} else {
int channel[2];
int r;
SYSCALL(r, pipe(channel), "pipe");
char *args[MAXARGS];
buildargs(msg.cmd_line, args);
if (fork() == 0) { // figlio
SYSCALL(r, close(channel[0]), "close reader");
SYSCALL(r, dup2(channel[1],1), "dup2 writer");
SYSCALL(r, close(channel[1]), "close writer");
execvp(args[0], &args[0]);
fprintf(stderr, "execvp fallita");
exit(EXIT_FAILURE);
} // padre
SYSCALL(r, close(channel[1]), "close writer");
SYSCALL(r, write(privatefifo,"\n",1), "write private fifo");
do {
SYSCALL(n, read(channel[0], buffer, PIPE_BUF), "read channel[0]");
SYSCALL(r, write(privatefifo,buffer,n), "write private fifo");
memset(buffer, 0x0, PIPE_BUF);
} while(n>0);
SYSCALL(r, close(channel[0]), "close reader");
SYSCALL(r, close(privatefifo), "close private fifo"); // invio EOF
done = 1;
}
}while(!done && n++ < 10);
if (!done) {
fprintf(stderr, "Il client non ha inviato il comando, condizione di fallimento\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
informatica/sol/laboratorio16/esercitazionia/fifoexample.txt · Ultima modifica: 13/04/2016 alle 13:21 (10 anni fa) da Massimo Torquati
