FIFO, pipe e socket di dominio Unix sono la stessa cosa nel kernel Linux?


30

Ho sentito che i FIFO si chiamano pipe. E hanno esattamente la stessa semantica. D'altra parte, penso che il socket del dominio Unix sia abbastanza simile al pipe (anche se non l'ho mai usato). Quindi mi chiedo se si riferiscano tutti alla stessa implementazione nel kernel Linux. Qualche idea?


Dalla risposta che segue ho capito che la mia domanda è in qualche modo ambigua ed è difficile avere una risposta. È probabile che nessuno possa conoscere così tanti dettagli delle cose implementative nel kernel (anche per gli sviluppatori del kernel). Se qualcuno può confermare che socket del dominio Unix, pipe e FIFO bufferizzano tutti i dati inviati nella memoria condivisa sotto Linux, la mia domanda è risolta. Bene ... parzialmente risolto.
Giustino,

FIFO = named pipe! = Pipe. I FIFO possono essere bidirezionali come una coppia di socket. I tubi normali sono unidirezionali. Tutti hanno l'interfaccia dei file e la semantica dei file. Perché l'implementazione è importante per te?
PSkocik,

So che le pipe sono buffer circolari e che con il sistema STREAMS possono avere un'implementazione condivisa, tuttavia Linux non utilizza STREAMS per impostazione predefinita. Credo che Linux codifichi questi canali IPC. Non mi va di controllare, però. : D Perché non lo fai? Il codice è disponibile al pubblico.
PSkocik,

Se condividono tutti la stessa implementazione, la loro efficienza dovrebbe essere ravvicinata. E, per me, il codice del kernel è troppo difficile da capire.
Giustino,

Risposte:


35

I socket di dominio UNIX e FIFO possono condividere una parte della loro implementazione, ma concettualmente sono molto diversi. FIFO funziona a un livello molto basso. Un processo scrive byte nel pipe e un altro legge da esso. Un socket di dominio UNIX ha lo stesso comportamento di un socket TCP / IP.

Un socket è bidirezionale e può essere utilizzato da molti processi contemporaneamente. Un processo può accettare molte connessioni sullo stesso socket e partecipare contemporaneamente a più client. Il kernel fornisce ogni volta un nuovo descrittore di file connect(2)o accept(2)viene chiamato sul socket. I pacchetti andranno sempre alla giusta procedura.
Su un FIFO, questo sarebbe impossibile. Per la comunicazione bidirezionale, hai bisogno di due FIFO e hai bisogno di una coppia di FIFO per ciascuno dei tuoi clienti. Non c'è modo di scrivere o leggere in modo selettivo, perché sono un modo molto più primitivo di comunicare.

Le pipe anonime e le FIFO sono molto simili. La differenza è che le pipe anonime non esistono come file nel filesystem, quindi nessun processo può open(2)farlo. Sono utilizzati da processi che li condividono con un altro metodo. Se un processo apre un FIFO e quindi esegue, ad esempio, a fork(2), il suo figlio erediterà i suoi descrittori di file e, tra questi, la pipe.

I socket di dominio UNIX, le pipe anonime e gli FIFO sono simili nel fatto che utilizzano segmenti di memoria condivisa. I dettagli dell'implementazione possono variare da un sistema all'altro, ma l'idea è sempre la stessa: collegare la stessa porzione di memoria in due processi distinti mappatura della memoria per farli condividere i dati
( modifica: sarebbe un modo ovvio per implementarlo ma è non come viene effettivamente eseguito in Linux, che utilizza semplicemente la memoria del kernel per i buffer, vedere la risposta di @ tjb63 di seguito).
Il kernel quindi gestisce le chiamate di sistema e estrae il meccanismo.


"I socket di dominio UNIX e FIFO possono condividere una parte della loro implementazione" ... il punto è "una parte di" ... Ho appena realizzato che la mia domanda è in qualche modo ambigua ed è difficile trovare una risposta. È probabile che nessuno possa conoscere così tanti dettagli di quali parti condividono nel kernel (anche per gli sviluppatori del kernel). Tuttavia ... qualcuno potrebbe confermare che socket di dominio Unix, pipe e FIFO tutti bufferano i dati inviati nella memoria condivisa sotto Linux? Se è confermato, la mia domanda è risolta. Bene ... parzialmente risolto.
Giustino,

Bene, sì, c'è un buffer gestito dal kernel. Ad esempio, con FIFO, puoi uccidere lo scrittore e il lettore può ancora ciò che è stato inviato nella pipa prima della morte dello scrittore. Con i socket, è un po 'più complicato perché funzionano con un protocollo collegato. Ma se invii, diciamo, un int al socket e poi esci dall'ambito in modo che l'int venga cancellato dallo stack del mittente, il destinatario può ancora leggerlo. Quindi, c'è chiaramente un buffer da qualche parte.
Lgeorget,

Rileggendo il commento, non sono sicuro di essere chiaro qui ... Fammi sapere se c'è ancora qualcosa di poco chiaro.
Lgeorget,

Il tuo commento mi è chiaro.
Giustino,

7

C'è una buona discussione di questo qui: http://www.slideshare.net/divyekapoor/linux-kernel-implementation-of-pipes-and-fifos

Per quanto posso vedere, sia dalle diapositive della presentazione, sia dalla fonte @ http://lxr.free-electrons.com/source/fs/pipe.c - i file FIFO sono implementati come un wrapper attorno a pipe, e gli stessi pipe sono implementato tramite il filesystem virtuale pipefs ..

@lgeorget - Le pipe sembrano usare la memoria del kernel per i buffer tra i lettori e gli autori - non usano la 'memoria condivisa' in quanto tale e copiano la memoria tra gli spazi degli indirizzi utente e del kernel (es. pipe_readchiamate pipe_iov_copy_to_user, che chiama __copy_to_user_inatomic(o copy_to_user) . __copy_to_user_inatomicchiamate copy_user_generic, che è uno tra diverse implementazioni ASM.


4

Una "FIFO" e una " named pipe" sono la stessa cosa, anche se è abbastanza diversa da come una shell gestisce una "pipe" (|) tra due comandi sulla riga di comando.

Una pipe denominata (FIFO) è un singolo "file" condiviso da due programmi, in cui uno scrive su di esso e l'altro letto da esso ... Un socket invece è una "connessione" tra due "file" - che può usare una rete ed essere su computer separati - dove un programma legge / scrive su un "file" e un altro programma legge / scrive sull'altro ... Non penso che siano così simili ... D'altra parte entrambi socket e named pipe - oltre a file, dispositivi, collegamenti simbolici - utilizzano tutti gli inode e implementano alcune funzionalità comuni (come lettura e scrittura).


1
Sì, il socket del dominio Unix è un tipo di socket, quindi l'API è simile ad altre API del socket come TCP o UDP, ecc. Tuttavia, il socket del dominio Unix può essere utilizzato solo come IPC "locale". E il modo in cui trasferisce i dati è la prima volta in assoluto, praticamente come FIFO e pipe. Quindi penso che sia possibile che l'API del socket del dominio Unix sia solo un altro incapsulamento di un'implementazione identica, quindi la usiamo come se fosse un socket. Penso che sia possibile che condividano tutti lo stesso interno nel kernel ... Voglio confermare se è vero o no.
Giustino,

1

Non penso proprio Justin. Se non sbaglio, e probabilmente lo sono, penso che i FIFO utilizzino un file su disco e che i socket del dominio Unix utilizzino la memoria del kernel.

Inoltre, come aggiunta al poster sopra che ha affermato che i socket di dominio Unix sono bidirezionali, questo è il caso solo quando si utilizza un socket SOCK_STREAM. SOCK_DGRAM I socket di dominio Unix sono, infatti, unidirezionali e possono solo inviare () dal codice che si chiama connect (), al codice che si chiama bind ().

Naturalmente, il codice che chiama connect () deve anche chiamare bind () per creare il proprio endpoint, ma ciò non ha nulla a che fare con la tua domanda.


3
Benvenuto su StackExchange e grazie per la pubblicazione. Alcune osservazioni ... 1) Se sbagli "molto probabilmente", dovresti ricontrollare prima di rispondere; questo sito non è un forum né una chat. 2) Grazie per la precisione sulle prese orientate al datagramma 3) Non è necessario pubblicare qualcosa che non ha "nulla a che fare" con la domanda. :)
lgeorget,

1

I miei 2 centesimi ... I socket FIFO e UNIX sono entrambi bidirezionali (simili) ma i socket hanno una topologia a stella mentre un FIFO è solo una coda (e quindi non può sostituirsi), sì la loro implementazione può condividere il codice internamente.

**

char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666);
fd = open(myfifo, O_RDWR);   //so that you can read/write to it
 ...
write(fd, buff1, sizeof(buff1));  
getchar();//wait till some one reds this and writes something else
int sz=read(fd, buff1, sizeof(buff1));  //read that something**

FIFO è bidirezionale?
jhfrontz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.