Newsgroup: it.comp.lang.c
Titolo: pipe con nome

Ho un problemino con le pipe con nome.
La mia domanda é:
Se creo una pipe con nome tramite mknod, e poi tramite essa faccio
comunicare due processi (uno in lettura e uno in scrittura) tramite
fgets ed fputs...
fgets ed fputs sono bloccanti? Ovvero, sono bloccanti come read e
write? Come nel caso delle pipe anonime si preoccupa il kernel di
gestire la sincronizzazione?
Mi faccio questa domanda perchè mi succede una cosa un pò strana con
il codice che riporto sotto (un client ed un server; il client legge
continuamente dei numeri dall'utente e li invia al server, il quale
stampa il quadrato dei numeri ricevuti e la somma progressiva).
Se mando in esecuzione il client in una shell ed il server in un'altra
shell, sembra tutto funzionare;
CLIENT:Inserisci un numero: 1
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 3
CLIENT:Inserisci un numero: 4
CLIENT:Inserisci un numero: 5
CLIENT:Inserisci un numero: 6
CLIENT:Inserisci un numero:
[mary@localhost pipe]$ ./fifoserver1
SERVER:Il quadrato di 1 è 1
SERVER:La somma progressiva fino a questo momento è 1
SERVER:Il quadrato di 2 è 4
SERVER:La somma progressiva fino a questo momento è 3
SERVER:Il quadrato di 3 è 9
SERVER:La somma progressiva fino a questo momento è 6
SERVER:Il quadrato di 4 è 16
SERVER:La somma progressiva fino a questo momento è 10
SERVER:Il quadrato di 5 è 25
SERVER:La somma progressiva fino a questo momento è 15
SERVER:Il quadrato di 6 è 36
SERVER:La somma progressiva fino a questo momento è 21
 se li mando in esecuzione nella stessa shell (il server in background)
ho questo errore:
[mary@localhost pipe]$ ./fifoserver1&
[1] 6364
[mary@localhost pipe]$ ./fifoclient1
CLIENT:Inserisci un numero: 1
SERVER:Il quadrato di 1 è 1
SERVER:La somma progressiva fino a questo momento è 1
Server:fgets() fallita: Invalid or incomplete multibyte or wide char
Da cosa dipende?
Proprio non lo riesco a capire :(
Invece, se sostituisco la fgets(dell'input) nel client con la scanf
commentata, se eseguo i due processi nella stessa shell, sembra
funzionare tutto bene per i primi numeri inseriti, poi il server sembra
prendere i numeri solo da 8 cifre;ovvero io inserisco un numero alla
volta, ma il server è come se li bufferizzasse.
...
CLIENT:Inserisci un numero: 567
SERVER:Il quadrato di 567 è 321489
SERVER:La somma progressiva fino a questo momento è 4641
CLIENT:Inserisci un numero: 567
SERVER:Il quadrato di 567 è 321489
SERVER:La somma progressiva fino a questo momento è 5208
CLIENT:Inserisci un numero: 567
CLIENT:Inserisci un numero: 56
CLIENT:Inserisci un numero: 6
CLIENT:Inserisci un numero: 6
CLIENT:Inserisci un numero: 6
CLIENT:Inserisci un numero: 6
CLIENT:Inserisci un numero: SERVER:Il quadrato di 567566666 è
1535715684
SERVER:La somma progressiva fino a questo momento è 567571874
Invece se li eseguo in due shell separate, fin dall'inizio il server
sembra "bufferizzare":
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero: 2
CLIENT:Inserisci un numero:
SERVER:Il quadrato di 222222222 è -1975004476
SERVER:La somma progressiva fino a questo momento è 222222222
Come mai questi strani comportamenti?
Ho provato di tutto...ma non riesco proprio a capire.
Il codice:
/* client */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define SIZE 10
#define FIFOFILENAME1 "myfifo1"
int main(int argc, char** argv){
char buf[10];
FILE* fp;
while(1){
	if( (fp=fopen(FIFOFILENAME1,"w"))==NULL){
		perror("C:fopen() fallita");
		exit(-1);
	}
	printf("CLIENT:Inserisci un numero: ");
	//scanf("%s",buf);
	if (fgets(buf,SIZE,stdin)==NULL){
	perror("S:fgets() fallita");
	exit(-2);
	}
	if(fputs(buf,fp)==EOF){
		perror("C:fputs() fallita");
		exit(-2);
	}
	fclose(fp);
	}
exit(0);
}
/* server */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
//#include <linux/stat.h>
#define SIZE 10
#define FIFOFILENAME1 "myfifo1"
int main(int argc, char** argv){
long int somma=0;
FILE* fp;
long int num;
char buf[10];
umask(0);
mknod(FIFOFILENAME1,S_IFIFO|0777,0);
while(1){
if ( (fp=fopen(FIFOFILENAME1,"r"))==NULL){
	perror("S:fopen() fallita");
	exit(-1);
}
//fp=fopen(FIFOFILENAME1,"r");
if (fgets(buf,SIZE,fp)==NULL){
	perror("Server:fgets() fallita");
	exit(-2);
}
//fgets(buf,SIZE,fp);
num=atoi(buf);
somma += num;
printf("SERVER:Il quadrato di %li è %li\nSERVER:La somma progressiva
fino a questo momento è %li\n\n", num,num*num,somma);
fclose(fp);
}
exit(0);
}
Mary

 Proprio non lo riesco a capire :(
Di preciso non lo so... non sono un esperto di pipe. In ogni caso
ho notato alcuni difetti nel codice che in qualche modo possono
influenzare (soprattutto il punto (3)).
1) crei la pipe nel server; ricorda pero`, che quando lanci un
    processo, non e` detto che questo venga eseguito immediatamente,
    sei solo sicura che entra nello stato READY; immagina questa
    situazione (veramente un caso limite): il server e` lanciato, ma
    non viene eseguito; il client viene lanciato e viene eseguito
    _prima_ del server. Il client crea un file regolare con il nome
    della pipe. Quando il server provera` a creare la pipe, mknod()
    fallira` (perche' il file e` gia` presente). Secondo me dovresti
    trovare un rimedio.
2) apri e chiudi la pipe per ogni operazione di lettura/scrittura.
    Non e` meglio farlo fuori dal ciclo while?
3) (possibile fonte di alcuni degli errori strani) la fputs() non
    inserisce nessun terminatore alla fine della stringa. Se il client
    riesce ad eseguire due fputs() di seguito, il server si ritrovera`
    una stringa che contiene la concatenazione dei due numeri e leggera`
    un valore sballato.
    Esempio
      C: scrive 4
      Pipe: 4
      C: scrive 4
      Pipe: 44
      S: legge 44 !errore!
Saluti,
Marco
-- 
To email me, remove the no_ and _spam from my address.

>un valore sballato.
Secondo me questo non si può verificare; percheè la fgets legge fino
a quando si verifica una di queste situazioni: fine del file, lettura
di un carattere di ritorno a capo o lettura di size-1 caratteri.
E, nel mio caso, siccome inserisco i numeri da input, dunque premendo
invio, la fgets troverà sempre un '\n'
aiuto...

[...]
Hai ragione, poi ho riflettuto sul fatto che la fgets() nel client legge
anche '\n' e questo viene spedito anche al server.
Guarda, sia su Advanced Programming in the Unix Environment che su
Unix for Programmers and Users quando vengono trattate le named pipe
gli autori non usano le routine stdio, ma le system call di Unix.
Prova a farlo anche tu, magari c'e` qualcosa che non va con l'uso
dello stdio.


Si, avevo notato anche io che usano sempre open, write, read...però
credevo fosse equivalente; e comunque adesso è diventata una specie di
sfida, soprattutto visto che il comportamento dipende dal numero delle
shell !?!
In ogni caso, grazie lo stesso.
Mary