File descriptor (deskryptor pliku) to nieujemna liczba całkowita, którą jądro Linuksa przypisuje każdemu otwartemu zasobowi w obrębie procesu: plikowi, gniazdu sieciowemu (socket), potokowi (pipe), a nawet urządzeniu. Mówiąc prościej, to taki numerek z szatni: oddajesz płaszcz (otwierasz plik), dostajesz numerek (deskryptor), a potem nie machasz całą garderobą, tylko podajesz numerek, gdy chcesz coś z tym zasobem zrobić.
Każdy proces ma własną tablicę deskryptorów. Trzy pierwsze numery są zarezerwowane konwencją: 0 to standard input (stdin, wejście), 1 to standard output (stdout, wyjście), a 2 to standard error (stderr, błędy). Gdy otwierasz kolejny plik, jądro zwykle przydziela najniższy wolny numer, więc pierwszy realnie otwarty plik dostaje zazwyczaj 3.
Deskryptory są tym, co spina cały model „wszystko jest plikiem” w Uniksie. Wywołania systemowe takie jak open(), read(), write() i close() operują właśnie na deskryptorach, a nie na nazwach plików. Dlatego ta sama funkcja read() czyta tak samo z pliku na dysku, jak i z gniazda TCP — bo dla procesu to po prostu numerek.
Przykład z praktyki
Przekierowania w shellu to deskryptory w czystej postaci. Komenda polecenie > out.log 2>&1 mówi: wyślij stdout (fd 1) do pliku out.log, a stderr (fd 2) skieruj tam, gdzie aktualnie wskazuje fd 1. Stąd klasyczny błąd: 2>&1 > out.log zadziała inaczej, bo kolejność ma znaczenie — najpierw kopiujesz cel fd 1 (jeszcze terminal), dopiero potem przekierowujesz fd 1 do pliku.
Żywe deskryptory procesu podejrzysz pod /proc/ albo komendą lsof -p . Przydaje się, gdy szukasz, kto trzyma otwarty plik blokujący odmontowanie dysku.
Na co uważać
- Wyciek deskryptorów — jeśli otwierasz pliki/gniazda i nie wołasz
close(), dobijasz do limitu (ulimit -n) i dostajeszEMFILE: too many open files. Klasyk w długo żyjących serwerach. - Deskryptor to nie to samo co i-węzeł (inode). To uchwyt procesu, a nie tożsamość samego pliku na dysku.
- Numery deskryptorów są lokalne dla procesu — fd
3w jednym programie nie ma nic wspólnego z fd3w innym.
Pojęcia powiązane: stdin/stdout/stderr, wywołania systemowe (open, read, write, close), socket, pipe, inode, lsof, ulimit, „wszystko jest plikiem”.