File descriptor

파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό ν•™μŠ΅ν•˜κΈ° μ•žμ„œ, κ³Όμ •μ˜ 이해λ₯Ό λ•λŠ” λ„€ κ°€μ§€ 핡심 μš©μ–΄λ₯Ό κ°„λ‹¨ν•˜κ²Œ μ •μ˜ν•˜κ² μŠ΅λ‹ˆλ‹€.

파일 λ””μŠ€ν¬λ¦½ν„° (File Descriptor, FD):

  • OS 컀널이 κ΄€λ¦¬ν•˜λŠ” μ—΄λ¦° νŒŒμΌμ΄λ‚˜ μ†ŒμΌ“ 같은 μžμ›(resource)에 λΆ€μ—¬ν•˜λŠ” 0 μ΄μƒμ˜ μ •μˆ˜ κ°’μž…λ‹ˆλ‹€.

    • 컀널이 μ—΄λ € μžˆλŠ” νŒŒμΌμ΄λ‚˜ μ†ŒμΌ“ 같은 μžμ›μ„ μ‹λ³„ν•˜κΈ° μœ„ν•΄ λΆ€μ—¬ν•˜λŠ” 0 μ΄μƒμ˜ μ •μˆ˜.

  • λ³΅μž‘ν•œ 컀널 λ‚΄λΆ€μ˜ μžμ›μ„ 'λŒ€κΈ° λ²ˆν˜Έν‘œ'처럼 λ‹¨μˆœν•œ 숫자둜 μΆ”μƒν™”ν•˜μ—¬, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‰½κ²Œ μžμ›μ„ μ œμ–΄ν•  수 있게 ν•΄μ£ΌλŠ” ν•Έλ“€(handle)μž…λ‹ˆλ‹€.

  • 즉, ν”„λ‘œμ„ΈμŠ€ κ΄€μ μ—μ„œλŠ” νŠΉμ • μžμ›μ„ κ°€λ¦¬ν‚€λŠ” μ°Έμ‘° κ°’μž…λ‹ˆλ‹€.

μ†ŒμΌ“ (Socket):

  • λ„€νŠΈμ›Œν¬ ν†΅μ‹ μ˜ 창ꡬ둜, λ„€νŠΈμ›Œν¬ 톡신을 μœ„ν•œ μ—”λ“œν¬μΈνŠΈ(endpoint). 컀널 λ ˆλ²¨μ—μ„œ κ΄€λ¦¬λ˜λŠ” 톡신 κ΄€λ ¨ 데이터 κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€.

  • IP μ£Όμ†Œμ™€ 포트 번호둜 μ‹λ³„λ˜λŠ” ν†΅μ‹ μ˜ 쒅착점(Endpoint)으둜, ν”„λ‘œμ„ΈμŠ€λŠ” 이 μ†ŒμΌ“μ„ 톡해 λ„€νŠΈμ›Œν¬λ‘œ 데이터λ₯Ό λ³΄λ‚΄κ±°λ‚˜ 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

μ‹œμŠ€ν…œ 콜 (System Call):

  • μ‚¬μš©μž μ˜μ—­(User-space)μ—μ„œ μ‹€ν–‰λ˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 컀널 μ˜μ—­(Kernel-space)의 κΈ°λŠ₯을 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ ν˜ΈμΆœν•˜λŠ” 곡식적인 μΈν„°νŽ˜μ΄μŠ€μž…λ‹ˆλ‹€.

  • socket(), bind(), accept() 와 같은 ν•¨μˆ˜λ“€μ΄ λŒ€ν‘œμ μΈ μ‹œμŠ€ν…œ μ½œμž…λ‹ˆλ‹€.

I/O λ©€ν‹°ν”Œλ ‰μ‹± (I/O Multiplexing):

  • 단일 ν”„λ‘œμ„ΈμŠ€/μŠ€λ ˆλ“œμ—μ„œ μ—¬λŸ¬ 개의 I/O μž‘μ—…μ„ λ™μ‹œμ— μ²˜λ¦¬ν•˜λŠ” κΈ°μˆ μž…λ‹ˆλ‹€.

  • select, poll, epoll(Linux), kqueue(BSD) 등이 λŒ€ν‘œμ μž…λ‹ˆλ‹€.

파일 λ””μŠ€ν¬λ¦½ν„°λŠ” μ–΄λ–»κ²Œ μƒμ„±λ˜λŠ”κ°€?

μƒˆλ‘œμš΄ 파일 λ””μŠ€ν¬λ¦½ν„°κ°€ μƒμ„±λ˜λŠ” 과정은 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μš”μ²­κ³Ό μ»€λ„μ˜ λ‚΄λΆ€ μž‘μ—…μ΄ 맞물렀 μ§„ν–‰λ©λ‹ˆλ‹€.

1단계: λ¦¬μŠ€λ‹ μ†ŒμΌ“ μ€€λΉ„

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λŠ” ν΄λΌμ΄μ–ΈνŠΈμ˜ 연결을 λ°›κΈ° μœ„ν•΄μ„œ λ‹€μŒκ³Ό 같은 μ‹œμŠ€ν…œ μ½œμ„ μˆœμ„œλŒ€λ‘œ ν˜ΈμΆœν•©λ‹ˆλ‹€.

  1. socket(): 컀널에 μ†ŒμΌ“ 생성을 μš”μ²­ν•©λ‹ˆλ‹€.

    • 컀널은 내뢀에 μ†ŒμΌ“ ꡬ쑰체λ₯Ό λ§Œλ“€κ³ , 이λ₯Ό κ°€λ¦¬ν‚€λŠ” 첫 번째 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— λ°˜ν™˜ν•©λ‹ˆλ‹€. (e.g., fd = 3)

    • 즉, 컀널은 μš”μ²­μ„ μˆ˜λ½ν•˜κ³  μ†ŒμΌ“μ„ μƒμ„±ν•œ λ’€, ν•΄λ‹Ή μ†ŒμΌ“μ„ κ°€λ¦¬ν‚€λŠ” 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

  2. bind(): μƒμ„±λœ μ†ŒμΌ“μ— νŠΉμ • IP μ£Όμ†Œμ™€ PORT 번호λ₯Ό λ°”μΈλ”©ν•©λ‹ˆλ‹€.

    • 이 μ†ŒμΌ“μ€ β€˜192.168.1.10:8080’ μ£Όμ†Œμ—μ„œλ§Œ μ‚¬μš©ν•  κ²λ‹ˆλ‹€.’ 라고 μ†ŒμΌ“μ— νŠΉμ • μ£Όμ†Œμ™€ 포트λ₯Ό λ°”μΈλ”©ν•©λ‹ˆλ‹€.

  3. listen(): μ†ŒμΌ“μ„ λ¦¬μŠ€λ‹ μƒνƒœλ‘œ μ „ν™˜ν•©λ‹ˆλ‹€.

    • 이 ν•¨μˆ˜ ν˜ΈμΆœμ„ 톡해 컀널은 이 μ†ŒμΌ“μ„ 톡해 λ“€μ–΄μ˜€λŠ” μ—°κ²° μš”μ²­μ„ 받아듀일 μ€€λΉ„λ₯Ό ν•©λ‹ˆλ‹€.

μ΄λ•Œ μƒμ„±λœ fd = 3은 λ¦¬μŠ€λ‹ μ†ŒμΌ“(Listening Socket)의 파일 λ””μŠ€ν¬λ¦½ν„°(FD)μž…λ‹ˆλ‹€.

이 FD의 역할은 였직 μ—°κ²° μš”μ²­μ„ λ°›λŠ” 것이지, μ‹€μ œ 데이터λ₯Ό μ£Όκ³ λ°›λŠ” μš©λ„κ°€ μ•„λ‹ˆλΌλŠ” μ μž…λ‹ˆλ‹€.

  • ⭐️ μ‹€μ œ 데이터 톡신에 직접 μ‚¬μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

2단계: μ—°κ²° 수립 (TCP Handshake) - μ»€λ„μ˜ μ—­ν• 

ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ˜ IP와 포트둜 μ—°κ²° μš”μ²­(SYN νŒ¨ν‚·)을 보내면, μ΄λ•ŒλΆ€ν„°λŠ” 컀널이 λ„€νŠΈμ›Œν¬ μ—°κ²° 수립의 μ „ 과정을 μ „λ‹΄ν•©λ‹ˆλ‹€.

  • 컀널은 SYN νŒ¨ν‚·μ„ μˆ˜μ‹ ν•˜κ³  SYN-ACK둜 μ‘λ‹΅ν•˜λ©°, ν΄λΌμ΄μ–ΈνŠΈμ˜ λ§ˆμ§€λ§‰ ACKλ₯Ό λ°›μ•„ TCP 3-Way Handshakeλ₯Ό μ™„λ£Œν•©λ‹ˆλ‹€.

  • 이 κ³Όμ • λ™μ•ˆ listen()을 ν˜ΈμΆœν•œ μ„œλ²„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μ•„λ¬΄λŸ° μ•Œλ¦Όλ„ λ°›μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 컀널이 λͺ¨λ“  과정을 λ…λ¦½μ μœΌλ‘œ μ²˜λ¦¬ν•˜μ—¬ 연결을 μ™„μ „νžˆ μˆ˜λ¦½ν•©λ‹ˆλ‹€.

    • 연결에 μ„±κ³΅ν•˜λ©΄ 컀널은 μ—°κ²° 정보λ₯Ό λ¦¬μŠ€λ‹ μ†ŒμΌ“μ— ν• λ‹Ήλœ completed connection queue에 μΆ”κ°€ν•©λ‹ˆλ‹€.

3단계: μƒˆ 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ 생성 (accept)

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λŠ” 보톡 accept() μ‹œμŠ€ν…œ μ½œμ„ ν˜ΈμΆœν•˜μ—¬ λΈ”λ‘œν‚Ή(blocking) μƒνƒœλ‘œ λŒ€κΈ°ν•©λ‹ˆλ‹€.

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λŠ” acceptλ₯Ό 호좜 후에 μž λ“€κ³ , μ»€λ„μ—κ²Œ μ—°κ²° μ™„λ£Œ 큐에 μƒˆλ‘œμš΄ 연결이 λ“€μ–΄μ˜€λ©΄ β€˜μ•Œλ €μ€˜β€™λΌκ³  μš”μ²­ν•©λ‹ˆλ‹€.

  • 즉, acceptλŠ” 컀널이 μ„œλ²„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—κ²Œ β€˜μƒˆ μ—°κ²° 도착’을 μ•Œλ €μ£ΌλŠ” μ‹ ν˜ΈλΌ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

컀널이 큐에 μƒˆλ‘œμš΄ 연결이 μžˆμŒμ„ ν™•μΈν•˜λ©΄, accept() ν˜ΈμΆœμ— μ‘λ‹΅ν•˜κΈ° μœ„ν•΄ λ‹€μŒ μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

  1. νμ—μ„œ κ°€μž₯ λ¨Όμ € λŒ€κΈ°ν•˜λ˜ μ—°κ²° 정보λ₯Ό κΊΌλƒ…λ‹ˆλ‹€.

  2. μ—°κ²° 정보λ₯Ό κ°€μ§€κ³  connection을 μœ„ν•œ μƒˆλ‘œμš΄ ν†΅μ‹ μš© μ†ŒμΌ“(connected socekt) ꡬ쑰체λ₯Ό 컀널 λ©”λͺ¨λ¦¬μ— μƒμ„±ν•©λ‹ˆλ‹€.

  3. μƒμ„±ν•œ μƒˆλ‘œμš΄ μ†ŒμΌ“μ„ κ°€λ¦¬ν‚€λŠ” 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό ν• λ‹Ή(생성)ν•©λ‹ˆλ‹€.

    • ν”„λ‘œμ„ΈμŠ€μ˜ 파일 λ””μŠ€ν¬λ¦½ν„° ν…Œμ΄λΈ”μ—μ„œ λΉ„μ–΄μžˆλŠ” κ°€μž₯ μž‘μ€ 번호λ₯Ό ν• λ‹Ήν•©λ‹ˆλ‹€.

  4. 이 μƒˆλ‘œμš΄ 파일 λ””μŠ€ν¬λ¦½ν„° 번호λ₯Ό μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—κ²Œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

μœ„μ™€ 같이 데이터 톡신에 μ‚¬μš©λ  FDλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 직접 λ§Œλ“œλŠ” 것이 μ•„λ‹ˆλΌ, μ—°κ²° μš”μ²­μ„ 받은 컀널이 λ§Œλ“€μ–΄μ„œ accept()의 λ°˜ν™˜κ°’μœΌλ‘œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— κ±΄λ„€μ£ΌλŠ” κ²ƒμž…λ‹ˆλ‹€.

  • μ„œλ²„λŠ” fd=3(λ¦¬μŠ€λ‹ μ†ŒμΌ“)μœΌλ‘œλŠ” 계속 μƒˆλ‘œμš΄ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μˆ˜λ¦½ν•˜κ³ , fd=4(μ—°κ²° μ†ŒμΌ“)μœΌλ‘œλŠ” μ—°κ²°λœ ν΄λΌμ΄μ–ΈνŠΈμ™€ 데이터λ₯Ό μ£Όκ³ λ°›μŠ΅λ‹ˆλ‹€.

효율적으둜 FD κ΄€λ¦¬ν•˜κΈ°

μˆ˜λ§Žμ€ ν΄λΌμ΄μ–ΈνŠΈ μš”μ²­μ΄ λ“€μ–΄μ˜€λ©΄ 이에 λŒ€μ‘ν•œ 파일 λ””μŠ€ν¬λ¦½ν„°κ°€ μƒμ„±λ©λ‹ˆλ‹€. μ„œλ²„λŠ” μ–΄λ–€ ν΄λΌμ΄μ–ΈνŠΈκ°€ 데이터λ₯Ό λ³΄λƒˆλŠ”μ§€ μ•ŒκΈ° μœ„ν•΄μ„œλŠ” FD듀을 계속 확인해야 ν•˜κ³  λͺ¨λ“  FD듀을 μˆœνšŒν•˜λ©΄μ„œ β€˜λ°μ΄ν„° μ™”λ‹ˆ?’라고 λ¬»λŠ” 것은 맀우 λΉ„νš¨μœ¨μ μΌ κ²ƒμž…λ‹ˆλ‹€.

μ΄λ•Œ I/O λ©€ν‹°ν”Œλ ‰μ‹± 기술인 epoll이 μ‚¬μš©λ©λ‹ˆλ‹€.

1단계: epoll_create()

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜(μ„œλ²„ ν”„λ‘œμ„ΈμŠ€)이 μ‹œμŠ€ν…œ μ½œμ„ ν˜ΈμΆœν•˜μ—¬ 컀널에 epoll μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ–΄ 달라고 μš”μ²­ν•©λ‹ˆλ‹€.

  • 이 epoll μΈμŠ€ν„΄μŠ€λŠ” κ°μ‹œν•  FD λͺ©λ‘μ„ λ‹΄λŠ” κ³΅κ°„μž…λ‹ˆλ‹€.

2단계: epoll_ctl()

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ accpet()둜 받은 FDλ₯Ό epoll μΈμŠ€ν„΄μŠ€μ— λ“±λ‘ν•˜κΈ° μœ„ν•΄ μ‹œμŠ€ν…œ μ½œμ„ ν˜ΈμΆœν•©λ‹ˆλ‹€.

  • 즉, β€˜μ΄ FDμ—μ„œ 읽을 데이터가 생기면 μ•Œλ €μ€˜β€™λΌκ³  컀널에 μš”μ²­ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

3단계: epoll_wait()

  • μ—­μ‹œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹œμŠ€ν…œ μ½œμ„ ν˜ΈμΆœν•©λ‹ˆλ‹€.

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ β€˜μ΄λ²€νŠΈκ°€ λ°œμƒν•  λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜κ² μŠ΅λ‹ˆλ‹€.’라고 컀널에 μ•Œλ¦¬κ³  λΈ”λ‘œν‚Ή μƒνƒœμ— λ“€μ–΄κ°‘λ‹ˆλ‹€.

  • 컀널은 μ΄λ²€νŠΈκ°€ λ°œμƒν•˜λŠ” 경우 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κΉ¨μ›Œ FD 정보λ₯Ό λ°˜ν™˜ν•΄μ£Όκ³ , μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ 이λ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

μ΄λ ‡κ²Œ μ„œλ²„λŠ” 수만 개의 FDλ₯Ό 직접 관리할 ν•„μš” 없이 νŠΉμ • FD둜 데이터가 μˆ˜μ‹ λ˜λ©΄ 컀널이 이λ₯Ό κ°μ§€ν•˜κ³ , epoll_wait()μ—μ„œ λŒ€κΈ° 쀑인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κΉ¨μ›Œ μ΄λ²€νŠΈκ°€ λ°œμƒν•œ FD λͺ©λ‘λ§Œμ„ μ •ν™•νžˆ μ•Œλ €μ€λ‹ˆλ‹€.

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ κ·Έ FD듀에 λŒ€ν•΄μ„œλ§Œ I/O μž‘μ—…μ„ μ²˜λ¦¬ν•˜λ©΄ λ˜λ―€λ‘œ, CPU λ‚­λΉ„ 없이 효율적으둜 μ—¬λŸ¬ 연결을 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

정리

파일 λ””μŠ€ν¬λ¦½ν„°μ˜ 생성 과정을 보면, 역할이 맀우 λͺ…ν™•ν•˜κ²Œ λΆ„λ¦¬λ˜μ–΄ μžˆμŒμ„ μ•Œ 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

  • 연결을 λ°›λŠ” μ±…μž„ (λ¦¬μŠ€λ‹ μ†ŒμΌ“): 였직 μƒˆλ‘œμš΄ 연결을 μˆ˜λ½ν•˜λŠ” 데만 μ§‘μ€‘ν•©λ‹ˆλ‹€.

  • 데이터λ₯Ό 톡신할 μ±…μž„ (μ—°κ²° μ†ŒμΌ“): 각 ν΄λΌμ΄μ–ΈνŠΈμ™€μ˜ μ‹€μ œ 톡신을 μ „λ‹΄ν•©λ‹ˆλ‹€.

  • 연결을 μ€‘μž¬ν•˜κ³  μžμ›μ„ ν• λ‹Ήν•  μ±…μž„ (컀널): λ„€νŠΈμ›Œν¬ handshakeλ₯Ό μ²˜λ¦¬ν•˜κ³ , μš”μ²­μ— 따라 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μƒμ„±ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μ „λ‹¬ν•©λ‹ˆλ‹€.

FD의 생성 및 관리 과정을 μš”μ•½ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  1. μ€€λΉ„: μ„œλ²„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ¦¬μŠ€λ‹ μ†ŒμΌ“μ„ 미리 μ€€λΉ„ν•©λ‹ˆλ‹€.

  2. μ—°κ²°: μ—°κ²° μš”μ²­κ³Ό 수립(Handshake)λŠ” 컀널이 μ „λ‹΄ν•˜μ—¬ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

  3. 생성: 연결이 μ™„λ£Œλ˜λ©΄, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ accpet() ν˜ΈμΆœμ— λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ 컀널이 μƒˆλ‘œμš΄ ν†΅μ‹ μš© FDλ₯Ό μƒμ„±ν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€.

  4. 관리: μƒμ„±λœ FDλ₯Ό μ–΄λ–»κ²Œ κ΄€λ¦¬ν• μ§€λŠ” μ„œλ²„μ˜ μ•„ν‚€ν…μ²˜μ— 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€. κ³ μ„±λŠ₯ μ„œλ²„μ˜ 경우, FDλ₯Ό epollκ³Ό 같은 I/O λ©€ν‹°ν”Œλ ‰μ‹± 도ꡬ에 λ“±λ‘ν•˜μ—¬ μ΅œμ†Œν•œμ˜ μžμ›μœΌλ‘œ μ—¬λŸ¬ 연결을 효율적으둜 μ²˜λ¦¬ν•˜λŠ” 방식을 μ„ νƒν•©λ‹ˆλ‹€.

Last updated