File descriptor — Unix va Unixga o‘xshash operatsion tizimlarda process ochgan kernel obyektiga murojaat qiluvchi manfiy bo‘lmagan kichik butun son. U oddiy fayl, socket, pipe, device, event manbasi yoki boshqa I/O resursini ifodalashi mumkin.
Descriptor jadvali
Har process o‘z file descriptor jadvaliga ega. Jadval entrysi kernel open file description obyektiga pointing qiladi; u current offset va status flaglarni saqlaydi. Bir nechta descriptor dup yoki fork orqali ayni open descriptionni bo‘lishishi mumkin, shuning uchun offset ham umumiy bo‘lishi ehtimoli bor.
Odatda 0 standard input, 1 standard output, 2 standard error. Shell redirection shu descriptorlarni file, pipe yoki device’ga qayta bog‘laydi:
command >output.log 2>error.log
Open va close
open() pathname’ni tekshirib kernel obyekt yaratadi va descriptor qaytaradi. read, write, fcntl, close kabi system calllar shu son bilan ishlaydi. Descriptor faqat process doirasida ma’noli; boshqa processdagi ayni 5 boshqa resursni bildiradi.
close() descriptor jadvalidagi entryni bo‘shatadi. Shu open descriptionga oxirgi reference yopilgach kernel resursni yakuniy ozod qiladi. Fayl pathname orqali o‘chirilgan bo‘lsa ham ochiq descriptor mavjud ekan disk bloklari process yopguncha saqlanishi mumkin.
File descriptor leak
Application connection yoki faylni yopmasa descriptorlar yig‘iladi. Limitga yetganda EMFILE — process limiti, ENFILE — system-wide limit xatosi chiqishi mumkin. Server yangi socket qabul qila olmay, fayl ocholmay qoladi.
Exception va early return yo‘llarida close kafolatlanadi. Python context manager, Java try-with-resources yoki Go defer kabi konstruktsiyalar yordam beradi. Connection pool resursni butunlay yopmay qayta ishlatishi mumkin, ammo poolga qaytarish ham majburiy.
Limitlar
Soft va hard limit ulimit -n yoki getrlimit orqali boshqariladi. Limitni ko‘tarish leakni tuzatmaydi, faqat vaqtni uzaytiradi. Yuqori concurrency server har clientga socket, upstream connection, log file va event descriptor ishlatishini hisoblaydi.
Systemd service limitlari shell limitidan farq qilishi mumkin. Container host kernel limitlarini bo‘lishadi; orchestrator va runtime sozlamalari tekshiriladi.
Inheritance va xavfsizlik
fork childga descriptor nusxalarini beradi. exec vaqtida close-on-exec flag qo‘yilmagan descriptor yangi programga meros qoladi. Sensitive file yoki listening socketning kutilmagan child processga o‘tishi security va lifecycle muammosini yaratadi.
O_CLOEXEC yoki FD_CLOEXEC race’siz yopilishni ta’minlash uchun ishlatiladi. Privilege dropdan oldin keraksiz descriptorlar yopiladi. Descriptor sonini foydalanuvchidan kelgan nazoratsiz index sifatida ishlatib bo‘lmaydi.
Event-driven I/O
select, poll, epoll va kqueue ko‘p descriptorning readiness holatini kuzatadi. select descriptor soni va maksimal qiymat bo‘yicha cheklangan; epoll/kqueue katta connection serverlarda samaraliroq model beradi.
Readiness “butun message tayyor” degani emas. Non-blocking socket qisman read/write qiladi, application buffer va protocol framingni boshqaradi.
Diagnostika
/proc/<pid>/fd, lsof va service metriclari ochiq descriptorlarni ko‘rsatadi. Faqat umumiy son emas, socket holati, deleted file, pipe va pathname kategoriyasi tahlil qilinadi. Descriptorlar doimiy o‘sishi leak alomati; trafik bilan ko‘tarilib tushishi normal pool xulqi bo‘lishi mumkin.
Descriptor sizib chiqishini aniqlashda jarayonning ochiq fayllar soni vaqt bo‘yicha kuzatiladi. Limitga yaqinlashish yangi socket, log yoki konfiguratsiya faylini ocholmaslikka olib kelib, asl sababdan uzoq joyda xato ko‘rsatishi mumkin.
Bog‘liq tushunchalar
System call, Open file description, Socket, Pipe, Standard streams, epoll, Resource limit, File descriptor leak