Capisco che "Tutto è un file" è uno dei concetti principali di Unix, ma i socket usano API diverse fornite dal kernel (come socket, sendto, recv, ecc.), Non come le normali interfacce del file system.
Come si applica questo "Tutto è un file" qui?
Capisco che "Tutto è un file" è uno dei concetti principali di Unix, ma i socket usano API diverse fornite dal kernel (come socket, sendto, recv, ecc.), Non come le normali interfacce del file system.
Come si applica questo "Tutto è un file" qui?
Risposte:
i socket utilizzano API diverse
Questo non è del tutto vero. Esistono alcune funzioni aggiuntive da utilizzare con i socket, ma è possibile utilizzare, ad esempio, normale read()
e write()
su un socket fd.
come si applica questo "Tutto è un file" qui?
Nel senso che è coinvolto un descrittore di file.
Se la tua definizione di "file" è una sequenza discreta di byte memorizzati in un filesystem, allora non tutto è un file. Tuttavia, se la tua definizione di file è più simile a un handle - un canale di informazione, ovvero una connessione I / O - allora "tutto è un file" inizia a dare più senso. Queste cose implicano inevitabilmente sequenze di byte, ma la loro provenienza o destinazione potrebbe differire contestualmente.
Non è davvero inteso alla lettera, tuttavia. Un demone non è un file, un demone è un processo; ma se stai facendo IPC, il tuo metodo di relazione con un altro processo potrebbe essere mitigato da entità di stile file.
"Tutto è un file" è solo un'esagerazione. Era un romanzo degli anni '70 ed era una caratteristica distintiva primaria di UNIX. Ma è solo un concetto di marketing, non una vera base di UNIX, perché ovviamente non è vero. Non è utile o sensato trattare TUTTO come un file.
La CPU è un file? Il tuo programma legge () una CPU per ottenere una nuova istruzione? La RAM è un file? Il tuo programma legge () il byte successivo?
Allora, c'erano tipi di sistemi operativi che ti davano un'API per un disco floppy e un'API diversa per un disco rigido, un'API diversa per il nastro magnetico e un mucchio di API diverse per terminali diversi e così via. I sistemi mainframe IBM avevano diversi tipi di file sui dischi rigidi e ti davano un'API diversa per ognuno di essi, che ci crediate o no! Quindi l'approccio UNIX "è un file", insieme all'approccio "stdin / stdout / stderr", ha portato un'astrazione molto elegante sia per gli utenti che per i programmatori.
Con la rete, questa particolare astrazione non ha funzionato. E non c'è nulla di male, solo un po 'meno eleganza generale e coerenza del sistema operativo. Ma funziona Vedi un file chiamato /dev/myinternetz/www/google/com/tcp/80
oggi sul tuo sistema? Puoi aprire (), scrivere () una query e leggere () la risposta in un bel HTML? No? Questo perché l'astrazione "è un file" non era molto utile per interagire in rete. In pratica non funzionerebbe troppo bene. Legge delle astrazioni che perdono in azione.
/dev/tcp/www.google.com/80
. Non è un vero file però - bash lo sta solo fingendo.
/dev/mem
o /dev/kmem
se lo desideri.
I socket sono file. Puoi usare read
e write
su un socket: sono equivalenti a chiamare recv
e send
con flags=0
. Li chiudi con close
. Puoi spostarli con dup
e gli amici se devi mescolare i descrittori di file. È possibile impostare alcuni flag con fcntl
e utilizzare il buffering stdio dopo la chiamata fdopen
. L'elenco continua. È molto importante, è possibile chiamare select
e poll
su qualsiasi tipo di file, inclusi i socket, quindi queste funzioni consentono a un programma di bloccare fino a quando non riceve input in qualsiasi modo semplicemente elencando i descrittori di file.
Esistono chiamate di sistema aggiuntive per alcuni tipi di socket ( recv
e send
, shutdown
ecc.), Come una chiamata di sistema aggiuntiva per dispositivi ( ioctl
).
Non tutti i file hanno nomi e, tra quelli che lo fanno, non vivono sempre nella struttura delle directory. Le pipe create da pipe
(ad esempio in una pipeline di shell) e le socket create da socketpair
non hanno nomi, ma sono comunque file. I socket creati da socket
hanno un nome la cui sintassi dipende dal dominio. Questo nome viene passato in una struct sockaddr
a bind
e altre funzioni. Per un AF_UNIX
socket Unix ( ), il nome è a struct sockaddr_un
, che è una famiglia e una stringa; a seconda della stringa, questo può essere un nome di file (i socket nominati possono essere creati con mknod
su molte varianti unix) oppure no (lo spazio dei nomi astratto). Per un AF_INET
socket IPv4 ( ), il nome è a struct sockaddr_in
, contenente un numero di porta e un indirizzo IP, più il protocol
dalla socket
chiamata.
Se sei stat
un socket, vedrai che ha un numero di inode e altre caratteristiche dei file normali, quindi lo classificherei come file sul filesystem. Esempio:
# file live
live: socket
# stat live
File: `live'
Size: 0 Blocks: 0 IO Block: 4096 socket
Device: fc03h/64515d Inode: 198817 Links: 1
Access: (0660/srw-rw----) Uid: (23129/ icinga) Gid: (23130/icinga-cmd)
Access: 2014-11-07 09:27:59.000000000 -0800
Modify: 2014-11-05 09:27:03.000000000 -0800
Change: 2014-11-05 09:27:03.000000000 -0800
11/17. Informazioni aggiuntive per Linux (ext3): un socket ha un inode (che è un blocco di 256 byte sul disco) ma non ha blocchi di dati (è possibile verificarlo estraendo l'inode ed esaminando i puntatori del blocco di dati; oppure eseguendo debugfs 'stat' che mostra un Blockcount di 0). Quindi, ha metadati di file (proprietario, gruppo, autorizzazioni, ecc.) Ma nessun contenuto di dati sul disco. Questo è identico a un normale file vuoto ( touch /tmp/foo
) che ha anche un conteggio blocchi di 0. Nel primo caso, il campo "tipo" nell'inode mostra "socket"; nel secondo caso mostra "file normale".
Riferimenti: struttura dell'inode ext2 ; stat
, dumpe2fs
e debugfs
comandi.
file
o stat
su lo rende un file.