¿Qué son los descriptores de archivos, explicados en términos simples?
¿Cuál sería una descripción más simplificada de los descriptores de archivos en comparación con la de Wikipedia? ¿Por qué son necesarios? Digamos, tomemos los procesos de Shell como ejemplo y ¿cómo se aplican?
¿Una tabla de procesos contiene más de un descriptor de archivo? ¿Si es así por qué?
En palabras simples, cuando abre un archivo, el sistema operativo crea una entrada para representar ese archivo y almacenar la información sobre ese archivo abierto. Entonces, si hay 100 archivos abiertos en su sistema operativo, habrá 100 entradas en el sistema operativo (en algún lugar del kernel). Estas entradas están representadas por números enteros como (...100, 101, 102....). Este número de entrada es el descriptor del archivo. Por lo tanto, es solo un número entero que representa de forma única un archivo abierto para el proceso. Si su proceso abre 10 archivos, entonces su tabla de Proceso tendrá 10 entradas para descriptores de archivos.
De manera similar, cuando abre un socket de red, también se representa mediante un número entero y se llama Socket Descriptor. Espero que entiendas.
Un descriptor de archivo es un identificador opaco que se utiliza en la interfaz entre el usuario y el espacio del kernel para identificar recursos de archivos/sockets. Por lo tanto, cuando usa open()
o socket()
(llamadas al sistema para interactuar con el kernel), se le proporciona un descriptor de archivo, que es un número entero (en realidad es un índice de la estructura u del proceso, pero eso no es importante). Por lo tanto, si desea interactuar directamente con el kernel, utilizando llamadas al sistema a read()
, etc. write()
, close()
el identificador que utiliza es un descriptor de archivo.
Hay una capa de abstracción superpuesta a las llamadas al sistema, que es la stdio
interfaz. Esto proporciona más funcionalidades/características que las llamadas básicas al sistema. Para esta interfaz, el identificador opaco que obtiene es a FILE*
, que devuelve la fopen()
llamada. Hay muchas funciones que utilizan la stdio
interfaz fprintf()
, fscanf()
, fclose()
, que están ahí para hacerle la vida más fácil. En C, stdin
, stdout
y stderr
son FILE*
, que en UNIX se asignan respectivamente a descriptores de archivos 0
, 1
y 2
.
Escúchalo desde la Boca del Caballo: APUE (Richard Stevens).
Para el kernel, todos los archivos abiertos se denominan descriptores de archivos. Un descriptor de archivo es un número no negativo.
Cuando abrimos un archivo existente o creamos un archivo nuevo, el kernel devuelve un descriptor de archivo al proceso. El kernel mantiene una tabla de todos los descriptores de archivos abiertos que están en uso. La asignación de descriptores de archivos es generalmente secuencial y se asignan al archivo como el siguiente descriptor de archivo libre del conjunto de descriptores de archivos libres. Cuando cerramos el archivo, el descriptor del archivo se libera y está disponible para su posterior asignación.
Vea esta imagen para más detalles:
Cuando queremos leer o escribir un archivo, identificamos el archivo con el descriptor de archivo que fue devuelto por la llamada a la función open() o create() , y lo usamos como argumento para read() o write() .
Es por convención que los shells del sistema UNIX asocian el descriptor de archivo 0 con la entrada estándar de un proceso, el descriptor de archivo 1 con la salida estándar y el descriptor de archivo 2 con el error estándar .
El descriptor de archivo varía de 0 a OPEN_MAX. El valor máximo del descriptor de archivo se puede obtener con ulimit -n
. Para obtener más información, consulte el capítulo 3 del Libro APUE.
Otras respuestas agregaron cosas geniales. Agregaré solo mis 2 centavos.
Según Wikipedia, lo sabemos con certeza: un descriptor de archivo es un número entero no negativo. Lo más importante que creo que falta sería decir:
Los descriptores de archivos están vinculados a un ID de proceso.
Sabemos que los descriptores de archivos más famosos son 0, 1 y 2. 0 corresponde a STDIN
, 1 a STDOUT
y 2 a STDERR
.
Digamos, tomemos los procesos de Shell como ejemplo y ¿cómo se aplican?
Mira este código
#>sleep 1000 &
[12] 14726
Creamos un proceso con el id 14726 (PID). Usando lsof -p 14726
podemos obtener cosas como esta:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sleep 14726 root cwd DIR 8,1 4096 1201140 /home/x
sleep 14726 root rtd DIR 8,1 4096 2 /
sleep 14726 root txt REG 8,1 35000 786587 /bin/sleep
sleep 14726 root mem REG 8,1 11864720 1186503 /usr/lib/locale/locale-archive
sleep 14726 root mem REG 8,1 2030544 137184 /lib/x86_64-linux-gnu/libc-2.27.so
sleep 14726 root mem REG 8,1 170960 137156 /lib/x86_64-linux-gnu/ld-2.27.so
sleep 14726 root 0u CHR 136,6 0t0 9 /dev/pts/6
sleep 14726 root 1u CHR 136,6 0t0 9 /dev/pts/6
sleep 14726 root 2u CHR 136,6 0t0 9 /dev/pts/6
La cuarta columna FD y la siguiente columna TIPO corresponden al Descriptor de archivo y al tipo de Descriptor de archivo.
Algunos de los valores para el FD pueden ser:
cwd – Current Working Directory
txt – Text file
mem – Memory mapped file
mmap – Memory mapped device
Pero el descriptor de archivo real se encuentra en:
NUMBER – Represent the actual file descriptor.
El carácter después del número, es decir, "1u", representa el modo en que se abre el archivo. r para leer, w para escribir, u para leer y escribir.
TIPO especifica el tipo de archivo. Algunos de los valores de TYPE son:
REG – Regular File
DIR – Directory
FIFO – First In First Out
Pero todos los descriptores de archivos son CHR: archivo especial de caracteres (o archivo de dispositivo de caracteres)
Ahora podemos identificar los descriptores de archivos para y STDIN
fácilmente con , o podemos ver los mismos si .STDOUT
STDERR
lsof -p PID
ls /proc/PID/fd
Tenga en cuenta también que la tabla de descriptores de archivos de la que el kernel realiza un seguimiento no es la misma que la tabla de archivos o la tabla de inodos. Estos están separados, como explicaron algunas otras respuestas.
Quizás se pregunte dónde están físicamente estos descriptores de archivos y qué se almacena, /dev/pts/6
por ejemplo, en
sleep 14726 root 0u CHR 136,6 0t0 9 /dev/pts/6
sleep 14726 root 1u CHR 136,6 0t0 9 /dev/pts/6
sleep 14726 root 2u CHR 136,6 0t0 9 /dev/pts/6
Bueno, /dev/pts/6
vive puramente en la memoria. Estos no son archivos normales, sino los llamados archivos de dispositivo de caracteres . Puedes comprobar esto con: ls -l /dev/pts/6
y comenzarán con c
, en mi caso crw--w----
.
Solo para recordar, la mayoría de los sistemas operativos tipo Linux definen siete tipos de archivos:
- Archivos regulares
- Directorios
- Archivos de dispositivo de caracteres
- Bloquear archivos del dispositivo
- Conectores de dominio local
- Tuberías con nombre (FIFO) y
- Enlaces simbólicos