Post

[OS] I/O Models

[OS] I/O Models

๐Ÿงฉ I/O Model

์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๊ฐ€ ํ•˜๋“œ์›จ์–ด์˜ ๋ฌผ๋ฆฌ์  ์‹ค์ฒด์— ๋‹ฟ๊ธฐ๊นŒ์ง€๋Š” ์šด์˜์ฒด์ œ๋ผ๋Š” ๊ฑฐ๋Œ€ํ•œ ์ค‘์žฌ์ž๊ฐ€ ๋†“์—ฌ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ธ์œ„์ ์ธ ์„ธ๊ณ„์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์Šค์Šค๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ธ ๊ถŒํ•œ์ด ์—†์œผ๋ฉฐ, ์˜ค์ง โ€˜์‹œ์Šคํ…œ ์ฝœ(System Call)โ€™์ด๋ผ๋Š” ์—„๊ฒฉํ•œ ํ†ต๋กœ๋ฅผ ํ†ตํ•ด ์ปค๋„(Kernel)์—๊ฒŒ ์ž‘์—…์„ ๋Œ€ํ–‰ํ•ด ๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์„ธ์Šค์˜ ์ถ”์ƒํ™”

์ปดํ“จํ„ฐ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋‘ ํ•˜๋“œ์›จ์–ด ๊ตฌ์„ฑ ์š”์†Œ์ธ CPU์™€ RAM์€ ๊ฐ๊ฐ ์—ฐ์‚ฐ์˜ ๋‡Œ์™€ ๋‹จ๊ธฐ ๊ธฐ์–ต ์žฅ์น˜๋กœ์„œ ๋งˆ๋”๋ณด๋“œ๋ฅผ ํ†ตํ•ด ๊ธด๋ฐ€ํžˆ ํ†ต์‹ ํ•ฉ๋‹ˆ๋‹ค. ์šด์˜์ฒด์ œ์˜ ๋ณธ์งˆ์ ์ธ ์—…๋ฌด๋Š” ์ด ๋ฌผ๋ฆฌ์ ์ธ ํ•˜๋“œ์›จ์–ด๋“ค ์œ„์— ํ”„๋กœ์„ธ์Šค(Process)๋ผ๋Š” ๊ทผ๋ณธ์ ์ธ ์ถ”์ƒํ™” ๊ณ„์ธต์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์†Œํ”„ํŠธ์›จ์–ด๋Š” ์ด ํ”„๋กœ์„ธ์Šค ๋‚ด๋ถ€์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ์ด๋Š” ํ•˜๋“œ์›จ์–ด์˜ ๋ณต์žกํ•œ ๋ฌผ๋ฆฌ์  ๋™์ž‘์„ ๊ฐ์ถ”๊ณ  ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ์ž์›์„ ์ ์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณดํ˜ธ๋œ ์šธํƒ€๋ฆฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์šด์˜์ฒด์ œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ด ๊ฐ€์ƒ์˜ ์„ธ๊ณ„๋Š” ๊ฐ•๋ ฅํ•œ ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์šฐ๋ฆฌ์—๊ฒŒ ๋งˆ์น˜ ์—ฌ๋Ÿฌ ํ”„๋กœ๊ทธ๋žจ์ด ๋™์‹œ์— ์‹คํ–‰๋˜๋Š” ๊ฒƒ ๊ฐ™์€ ํ™˜์ƒ์„ ์‹ฌ์–ด์ค๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” ํ•˜๋‚˜์˜ CPU ์ฝ”์–ด๊ฐ€ ์ˆ˜ ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„๋กœ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ฒˆ๊ฐˆ์•„ ๊ฐ€๋ฉฐ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ, CPU๋Š” ์ดˆ๋‹น ์ˆ˜์‹ญ์–ต ๊ฐœ์˜ ๋ช…๋ น์–ด๋ฅผ ์ฒ˜๋ฆฌํ•  ๋งŒํผ ์••๋„์ ์œผ๋กœ ๋น ๋ฅด๊ธฐ์— ์ธ๊ฐ„์€ ๊ทธ ํ‹ˆ์ƒˆ๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ •๊ตํ•œ ์‹œ๊ฐ„ ์ชผ๊ฐœ๊ธฐ(Time-slicing) ๊ธฐ์ˆ  ๋•๋ถ„์— ์šฐ๋ฆฌ๋Š” ํ•˜๋“œ์›จ์–ด์˜ ๋ฌผ๋ฆฌ์  ๊ฐœ์ˆ˜๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์€ ์ˆ˜์˜ ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋…ผ๋ฆฌ์  ํ’์š”๋กœ์›€์„ ๋ˆ„๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ๊ฐ€์ƒ์˜ ํ’์š”๋กœ์›€์€ ๊ฒฐ์ฝ” ๊ณต์งœ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๋ฅผ ์ „ํ™˜ํ•  ๋•Œ๋งˆ๋‹ค ์šด์˜์ฒด์ œ๋Š” ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค์˜ ๋ ˆ์ง€์Šคํ„ฐ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ปค๋„ ๋ชจ๋“œ๋กœ ์ง„์ž…ํ•˜๋ฉฐ ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋“ฑ์˜ ๋ณต์žกํ•œ ๋’ท์ •๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ „ํ™˜ ์ž‘์—…์ด ํ˜„๋Œ€์ ์ธ ์‹œ์Šคํ…œ์—์„œ๋„ ์ƒ๋‹นํ•œ ์„ฑ๋Šฅ ๋น„์šฉ์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ I/O ๋ชจ๋ธ์„ ๊นŠ๊ฒŒ ์ดํ•ดํ•œ๋‹ค๋Š” ๊ฒƒ์€, ์šด์˜์ฒด์ œ๊ฐ€ ๊ตฌ์ถ•ํ•œ ํ”„๋กœ์„ธ์Šค๋ผ๋Š” ์ถ”์ƒํ™” ์ด๋ฉด์—์„œ ํ•˜๋“œ์›จ์–ด ์ž์›์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋ฐฐ๋ถ„๋˜๊ณ  ์†Œ๋ชจ๋˜๋Š”์ง€๋ฅผ ๊ฟฐ๋šซ์–ด ๋ณด๋Š” ๊ณผ์ •๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์™œ ์ง€์—ฐ๋˜๋Š”๊ฐ€

์—”์ง€๋‹ˆ์–ด๋ง ๊ด€์ ์—์„œ I/O๋Š” โ€˜์ง€์—ฐ๊ณผ์˜ ์ „์Ÿโ€™์ž…๋‹ˆ๋‹ค. CPU๊ฐ€ ์ดˆ๋‹น ์ˆ˜์‹ญ์–ต ๊ฐœ์˜ ๋ช…๋ น์–ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋™์•ˆ, ๋””์Šคํฌ๋‚˜ ๋„คํŠธ์›Œํฌ๋Š” ๊ทธ๋ณด๋‹ค ์ˆ˜๋งŒ ๋ฐฐ ๋А๋ฆฐ ์†๋„๋กœ ๋ฐ˜์‘ํ•ฉ๋‹ˆ๋‹ค.

  • CPU ์œ ํœด ์‹œ๊ฐ„: ํ•˜๋“œ ๋“œ๋ผ์ด๋ธŒ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ์™ธ๋ถ€ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ, CPU๋Š” ์•„๋ฌด๋Ÿฐ ์œ ์šฉํ•œ ์ž‘์—…๋„ ํ•˜์ง€ ๋ชปํ•œ ์ฑ„ โ€˜๋Œ€๊ธฐ(Waiting)โ€™ ์ƒํƒœ๋กœ ์ „์ด๋ฉ๋‹ˆ๋‹ค.
  • ๋ฌธ๋งฅ ์ „ํ™˜(Context Switching): ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค๊ฐ€ I/O๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ์ž๋ฆฌ๋ฅผ ๋น„์šธ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ „ํ™˜ ๋น„์šฉ์€ ์•ฝ 5๋งˆ์ดํฌ๋กœ์ดˆ์— ๋‹ฌํ•˜๋ฉฐ, ์ด๋Š” ์ˆ˜๋งŒ ๊ฐœ์˜ ๋ช…๋ น์–ด ์‹คํ–‰ ๊ธฐํšŒ๋ฅผ ์†Œ๋น„ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ๋ณต์‚ฌ์™€ ๋ฉ”๋ชจ๋ฆฌ ๊ฒฝ๊ณ„์„ 

๋‹จ์ˆœํžˆ ๊ธฐ๋‹ค๋ฆผ๋งŒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ํ•˜๋“œ์›จ์–ด์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊นŒ์ง€ ์ „๋‹ฌ๋˜๋Š” ๊ณผ์ •์—๋Š” โ€˜๋ฐ์ดํ„ฐ ๋ณต์‚ฌ(Data Copy)โ€™๋ผ๋Š” ์ˆจ์€ ๋น„์šฉ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  1. ์ปค๋„ ๋ฒ„ํผ ์œ ์ž…: ํ•˜๋“œ์›จ์–ด ์žฅ์น˜ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ฝ์–ด์˜จ ๋ฐ์ดํ„ฐ๊ฐ€ ์ปค๋„ ์˜์—ญ์˜ ๋ฉ”๋ชจ๋ฆฌ์— ๋จผ์ € ์ฑ„์›Œ์ง‘๋‹ˆ๋‹ค.
  2. ์œ ์ € ์˜์—ญ ๋ณต์‚ฌ: ์ปค๋„์€ ์ž์‹ ์˜ ๋ฒ„ํผ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์œ ์ € ์˜์—ญ ๋ฉ”๋ชจ๋ฆฌ๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ์ด์ค‘์ ์ธ ๋ณต์‚ฌ ๊ณผ์ •์€ ๋ฉ”๋ชจ๋ฆฌ ๋Œ€์—ญํญ์„ ์†Œ๋ชจํ•˜๊ณ  CPU ๋ถ€ํ•˜๋ฅผ ๋™๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ๊ณ ์„ฑ๋Šฅ ์‹œ์Šคํ…œ์„ ์„ค๊ณ„ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ด ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„๊ณผ CPU์˜ ๋Œ€๊ธฐ ์ƒํƒœ๋ฅผ ์–ผ๋งˆ๋‚˜ ์ •๊ตํ•˜๊ฒŒ ์žฅ์•…ํ•˜๋А๋ƒ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

I/O ๋ชจ๋ธ ์„ ํƒ์˜ ๋ณธ์งˆ

์–ด๋–ค I/O ๋ชจ๋ธ์„ ์„ ํƒํ•˜๋А๋ƒ๋Š” ๊ฒฐ๊ตญ โ€œCPU๊ฐ€ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ ๋ฌธ์„ ์ž ๊ทธ๊ณ  ๊ธฐ๋‹ค๋ฆด ๊ฒƒ์ธ๊ฐ€, ์•„๋‹ˆ๋ฉด ๋‹ค๋ฅธ ์ผ์„ ํ•˜๋ฉฐ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•  ๊ฒƒ์ธ๊ฐ€โ€์— ๋Œ€ํ•œ ์ „๋žต์  ๊ฒฐ์ •์ž…๋‹ˆ๋‹ค.

๐Ÿงฉ Blocking

๊ฐ€์žฅ ์ง๊ด€์ ์ด๋ฉฐ ์›์ดˆ์ ์ธ ์ด ๋ชจ๋ธ์€ โ€˜๊ธฐ๋‹ค๋ฆผโ€™์„ ์—”์ง€๋‹ˆ์–ด๋ง์˜ ์ค‘์‹ฌ์— ๋‘ก๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๊ฐ€ ์†Œ์ผ“์—์„œ read()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ˆœ๊ฐ„, ์ปค๋„ ๋ฒ„ํผ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ์‹คํ–‰ ํ๋ฆ„์€ ๊ทธ ์ž๋ฆฌ์—์„œ ์ฆ‰์‹œ ๋ฉˆ์ถฐ ์„œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ˆœํžˆ ์ฝ”๋“œ์˜ ํ•œ ์ค„์ด ๋ฉˆ์ถ”๋Š” ๊ฒƒ์„ ๋„˜์–ด, ์šด์˜์ฒด์ œ ์ˆ˜์ค€์—์„œ ํ”„๋กœ์„ธ์Šค์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๊ฐ€ ์ผ์‹œ์ ์œผ๋กœ ์ค‘๋‹จ๋จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์šด์˜์ฒด์ œ์˜ ํ•ต์‹ฌ ์—ญํ• ์€ ํ•˜๋“œ์›จ์–ด ์ž์›์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ, Blocking ํ˜ธ์ถœ ์‹œ ์ปค๋„์€ ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๋ฅผ โ€˜์‹คํ–‰(Running)โ€™ ์ƒํƒœ์—์„œ โ€˜๋Œ€๊ธฐ(Waiting)โ€™ ์ƒํƒœ๋กœ ์ „์ด์‹œ์ผœ CPU ์Šค์ผ€์ค„๋ง ๋Œ€์ƒ์—์„œ ์™„์ „ํžˆ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ ์ปค๋„์€ ํ”„๋กœ์„ธ์Šค์˜ ๋ฌธ๋งฅ(Context)์„ ์ €์žฅํ•˜๊ณ , ํ”„๋กœ์„ธ์Šค ์ œ์–ด ๋ธ”๋ก(PCB)์„ ์‹คํ–‰ ํ์—์„œ ์ œ๊ฑฐํ•˜์—ฌ ํŠน์ • ์žฅ์น˜์˜ wait_queue๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค. CPU๋Š” ์ด์ œ ํ•  ์ผ์ด ์—†์–ด์ง„ ๋Œ€๊ธฐ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋– ๋‚˜ ๋‹ค๋ฅธ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ž‘์—…์„ ์ฐพ์•„ ๋– ๋‚˜๋Š”๋ฐ, ์ด ๋ฌธ๋งฅ ์ „ํ™˜ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ง€์—ฐ์ด ์•ฝ 5๋งˆ์ดํฌ๋กœ์ดˆ์— ๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” CPU๊ฐ€ ์ˆ˜๋งŒ ๊ฐœ์˜ ๋ช…๋ น์–ด๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ฒœ๊ธˆ ๊ฐ™์€ ๊ธฐํšŒ๋ฅผ ๋‹จ์ˆœํžˆ โ€˜์ž‘์—… ํ™˜๊ฒฝ์„ ๊ต์ฒดํ•˜๋Š” ๋ฐโ€™ ์จ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ•˜๋“œ์›จ์–ด์™€ ์ปค๋„ ์‚ฌ์ด์˜ ๋ณต์žกํ•œ ์ƒํ˜ธ์ž‘์šฉ, ์ฆ‰ ์‹œ์Šคํ…œ ์ฝœ ํ˜ธ์ถœ๋ถ€ํ„ฐ ํŠธ๋žฉ(Trap) ๋ฐœ์ƒ, ์ปค๋„ ๋ฒ„ํผ ํ™•์ธ, ํ”„๋กœ์„ธ์Šค ์ˆ˜๋ฉด ์ƒํƒœ ์ง„์ž…, ๊ทธ๋ฆฌ๊ณ  ์ธํ„ฐ๋ŸฝํŠธ์— ์˜ํ•œ ๊นจ์–ด๋‚จ์œผ๋กœ ์ด์–ด์ง€๋Š” ์ผ๋ จ์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์•„๋ž˜์˜ ์ฝ”๋“œ ๊ตฌ์กฐ ์†์— ์ƒ์„ธํžˆ ๋…น์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

/**
 * C ๊ธฐ๋ฐ˜ Blocking ์†Œ์ผ“ I/O ๋ฉ”์ปค๋‹ˆ์ฆ˜
 * * ์ด ์ฝ”๋“œ๋Š” ๊ฐ€์žฅ ์ „ํ˜•์ ์ธ Blocking ๋ชจ๋ธ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
 * ์šด์˜์ฒด์ œ๋Š” ํ•˜๋“œ์›จ์–ด ์ž์›์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด 
 * ํ”„๋กœ์„ธ์Šค์— ์ง์ ‘์ ์ธ ์ œ์–ด๊ถŒ์„ ์ฃผ์ง€ ์•Š๊ณ  '์‹œ์Šคํ…œ ์ฝœ'์ด๋ผ๋Š” ์ค‘์žฌ์•ˆ์„ ์ œ์‹œํ•ฉ๋‹ˆ๋‹ค.
 */
void start_blocking_server(int client_fd) {
    char buffer[1024];

    printf("๋ฐ์ดํ„ฐ ์ˆ˜์‹  ๋Œ€๊ธฐ ์ค‘...\n");

    /* * 1. ์‹œ์Šคํ…œ ์ฝœ ์ง„์ž… (Trap):
     * ์œ ์ € ๋ชจ๋“œ์—์„œ ์ปค๋„ ๋ชจ๋“œ๋กœ ์‹คํ–‰ ๊ถŒํ•œ์ด ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.
     * * 2. ์ปค๋„ ๋ฒ„ํผ ํ™•์ธ:
     * ์ปค๋„์€ ํ•ด๋‹น ์†Œ์ผ“์˜ ์ˆ˜์‹  ๋ฒ„ํผ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
     * * 3. ํ”„๋กœ์„ธ์Šค ์ž ๋“ค๊ธฐ (Waiting State):
     * ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋ฉด, ์ปค๋„์€ ์ด ์Šค๋ ˆ๋“œ์˜ PCB(Process Control Block)๋ฅผ 
     * ์‹คํ–‰ ํ์—์„œ ์ œ๊ฑฐํ•˜๊ณ  'Wait Queue'๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค.
     * * 4. ๋ฌธ๋งฅ ์ „ํ™˜ (Context Switch):
     * CPU๋Š” ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ๋ ˆ์ง€์Šคํ„ฐ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Ÿฌ ๋– ๋‚ฉ๋‹ˆ๋‹ค. 
     * ์ด ์ „ํ™˜์— ์•ฝ 5๋งˆ์ดํฌ๋กœ์ดˆ๊ฐ€ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.
     */
    ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer)); 

    /*
     * 5. ์ธํ„ฐ๋ŸฝํŠธ ๋ฐ ๊นจ์–ด๋‚จ (Ready State):
     * ์žฅ์น˜ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜๋ฉด CPU์— ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ณด๋‚ด๊ณ , 
     * ์ปค๋„์€ ์ž ๋“ค์—ˆ๋˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค์‹œ 'Ready' ์ƒํƒœ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
     * * 6. ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ ๋ฐ ๋ณต๊ท€:
     * ์ปค๋„ ๋ฒ„ํผ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ € ์˜์—ญ์˜ buffer[]๋กœ ๋ณต์‚ฌ๋œ ํ›„, 
     * ๋น„๋กœ์†Œ read() ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋˜๋ฉฐ ์ œ์–ด๊ถŒ์ด ๋‹ค์‹œ ์œ ์ €์—๊ฒŒ ๋Œ์•„์˜ต๋‹ˆ๋‹ค.
     */
    if (bytes_read > 0) {
        printf("์ˆ˜์‹  ๋ฐ์ดํ„ฐ: %.*s\n", (int)bytes_read, buffer);
    }

    close(client_fd);
}

Blocking ๋ชจ๋ธ์˜ ์ง„์ •ํ•œ ์œ„ํ˜‘์€ ๋‹จ์ˆœํ•œ ์‹œ๊ฐ„ ์ง€์—ฐ๋ณด๋‹ค โ€˜์ž์› ์˜ค์—ผโ€™์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ CPU์—์„œ ์ซ“๊ฒจ๋‚  ๋•Œ, ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ฌ์šฉํ•˜๋˜ L1, L2 ์บ์‹œ ๋ฐ์ดํ„ฐ๋Š” ๋ฌดํšจํ™”(Flush)๋ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋„์ฐฉํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋‹ค์‹œ ๋ณต๊ท€ํ–ˆ์„ ๋•Œ ์ง๋ฉดํ•˜๋Š” โ€˜์บ์‹œ ๋ฏธ์Šค(Cache Miss)โ€™๋Š” ์‹œ์Šคํ…œ์˜ ์ „์ฒด์ ์ธ ์ฒ˜๋ฆฌ๋Ÿ‰(Throughput)์„ ๊ฐ‰์•„๋จน๋Š” ์ฃผ๋ฒ”์ด ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ๊ณ ์ „์ ์ธ โ€˜์—ฐ๊ฒฐ๋‹น ์Šค๋ ˆ๋“œ ํ•˜๋‚˜โ€™ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ์ˆ˜๋งŒ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ์ž Blocking ์ƒํƒœ๋กœ ์ž ๋“ค๊ฒŒ ๋˜๋ฉด ์ปค๋„์€ ์ด๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์ „ํ™˜ํ•˜๋Š” ๋น„์šฉ๋งŒ์œผ๋กœ ์ „์ฒด ์ž์›์˜ ์ƒ๋‹น ๋ถ€๋ถ„์„ ํƒ•์ง„ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Blocking I/O์˜ ๊ตฌํ˜„์  ๊ฐ€์น˜

Blocking ๋ชจ๋ธ์€ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ด€์ ์—์„œ๋Š” ๋ถˆ๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ์ˆœ์ฐจ์  ํ๋ฆ„๊ณผ ์ฝ”๋“œ์˜ ์‹คํ–‰ ํ๋ฆ„์ด 1:1๋กœ ์ผ์น˜ํ•œ๋‹ค๋Š” ๊ฐ•๋ ฅํ•œ ๊ฐ•์ ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด๋Š” ๋””๋ฒ„๊น…์˜ ์šฉ์ด์„ฑ๊ณผ ์ฝ”๋“œ์˜ ๋ช…ํ™•์„ฑ์„ ๋ณด์žฅํ•˜๋ฏ€๋กœ, ๋™์‹œ์„ฑ๋ณด๋‹ค๋Š” ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์˜ ์ •ํ™•์„ฑ๊ณผ ์„ ํ›„ ๊ด€๊ณ„๊ฐ€ ํ•ต์‹ฌ์ธ ๊ธˆ์œต๊ถŒ์˜ ๋ฐฐ์น˜ ์ž‘์—…์ด๋‚˜ ํŠธ๋žœ์žญ์…˜ ๋„๋ฉ”์ธ์—์„œ ์—ฌ์ „ํžˆ ํ‘œ์ค€์ ์ธ ์ „๋žต์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๐Ÿงฉ Non-Blocking

Non-Blocking ๋ชจ๋ธ์€ ์‹œ์Šคํ…œ ์ฝœ์˜ ๋ฐ˜ํ™˜ ์‹œ์ ์„ ๋น„ํ‹€์–ด Blocking์˜ ๊ณ ์งˆ์ ์ธ ๋ฌธ์ œ์ธ โ€˜๋Œ€๊ธฐ ์ƒํƒœ๋กœ์˜ ์ „์ดโ€™๋ฅผ ์ •๋ฉด์œผ๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ปค๋„์— ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ–ˆ์„ ๋•Œ, ์ค€๋น„๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋ฉด ์ปค๋„์€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ž ์žฌ์šฐ๋Š” ๋Œ€์‹  ์ฆ‰์‹œ ์—๋Ÿฌ ์ฝ”๋“œ(EAGAIN ํ˜น์€ EWOULDBLOCK)๋ฅผ ์œ ์ € ์ŠคํŽ˜์ด์Šค๋กœ ๋˜์ง‘๋‹ˆ๋‹ค. ์šด์˜์ฒด์ œ์˜ ํ•ต์‹ฌ ์—ญํ• ์€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์“ฐ๊ฒŒ ๋•๋Š” ๊ฒƒ์ด๋ฉฐ, Non-Blocking ํ˜ธ์ถœ์€ ํ”„๋กœ์„ธ์Šค๊ฐ€ โ€˜๋Œ€๊ธฐ(Waiting)โ€™ ์ƒํƒœ๋กœ ๋น ์ง€์ง€ ์•Š๊ณ  โ€˜์‹คํ–‰(Running)โ€™ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒฐ์ •์ ์ธ ๋™๋ ฅ์ด ๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๋Š” ์ œ์–ด๊ถŒ์„ ์žƒ์ง€ ์•Š์•˜๊ธฐ์— ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  ๋‹ค์Œ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ๋˜ ๋‹ค๋ฅธ I/O ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉฐ CPU ์ž์›์„ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ ์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒ๋ฆฌ๋ฅผ ํ™•๋ณดํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ž์œ ์˜ ๋Œ€๊ฐ€๋Š” โ€˜๋ฐ˜๋ณต์ ์ธ ์งˆ์˜(Polling)โ€™๋ผ๋Š” ํ˜•๋ฒŒ๋กœ ๋Œ์•„์˜ต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์–ธ์ œ ์ค€๋น„๋ ์ง€ ์•Œ ์ˆ˜ ์—†๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ปค๋„์—๊ฒŒ ์ƒํƒœ๋ฅผ ๋Š์ž„์—†์ด ์žฌํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐ”์œ ๋Œ€๊ธฐ(Busy Wait)๋Š” CPU ์‚ฌ์šฉ๋ฅ ์„ ๋ฌด์˜๋ฏธํ•˜๊ฒŒ ์น˜์†Ÿ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋„์ฐฉํ•˜์ง€ ์•Š์€ ์ฐฐ๋‚˜์˜ ์ˆœ๊ฐ„์—๋„ CPU๋Š” ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋Š” ์œ ์ € ๋ชจ๋“œ์™€ ์ปค๋„ ๋ชจ๋“œ๋ฅผ ์˜ค๊ฐ€๋Š” โ€˜๋ชจ๋“œ ์ „ํ™˜(Mode Switching)โ€™ ๋น„์šฉ์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์ด ํ”„๋กœ์„ธ์Šค ๊ฐ„์˜ ๋ฌผ๋ฆฌ์ ์ธ ์ „ํ™˜ ๋น„์šฉ์ด๋ผ๋ฉด, Non-Blocking์˜ Polling์€ โ€˜๋นˆ ์„œ๋ž์„ ์ˆ˜๋งŒ ๋ฒˆ ์—ด์–ด๋ณด๋Š” ์œ ์ €/์ปค๋„ ๊ฒฝ๊ณ„ ์™•๋ณต ๋น„์šฉโ€™์— ๋น„์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ•˜๋“œ์›จ์–ด์™€ ์ปค๋„ ์‚ฌ์ด์˜ ์ƒํ˜ธ์ž‘์šฉ, ํŠนํžˆ ์ œ์–ด๊ถŒ์˜ ์ฆ‰์‹œ ๋ฐ˜ํ™˜๊ณผ EAGAIN ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋ฉฐ CPU๊ฐ€ ์‰ฌ์ง€ ์•Š๊ณ  ํšŒ์ „(Spin)ํ•˜๋Š” ๊ณผ์ •์€ ์•„๋ž˜์˜ ์ฝ”๋“œ ๊ตฌ์กฐ ์†์— ์ƒ์„ธํžˆ ๋…น์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>

/**
 * Non-Blocking ์†Œ์ผ“ ์„ค์ • ๋ฐ Polling ๋ฉ”์ปค๋‹ˆ์ฆ˜
 * * Non-Blocking ๋ชจ๋ธ์˜ ํ•ต์‹ฌ์€ '๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š” ์šฉ๊ธฐ'์™€ '๋Š์ž„์—†๋Š” ํ™•์ธ'์— ์žˆ์Šต๋‹ˆ๋‹ค.
 * ํ”„๋กœ์„ธ์Šค๋Š” Waiting ์ƒํƒœ๋กœ ์ „์ด๋˜์ง€ ์•Š๊ณ  
 * ๊ณ„์† CPU๋ฅผ ์ ์œ ํ•˜๋ฉฐ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒ๋ฆฌ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
 */
void start_non_blocking_polling(int sockfd) {
    char buffer[1024];

    // 1. ์†Œ์ผ“์„ Non-Blocking ๋ชจ๋“œ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    // ์ด์ œ ์ด ์†Œ์ผ“์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์‹œ์Šคํ…œ ์ฝœ์€ ์ œ์–ด๊ถŒ์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    printf("๋น„์ฐจ๋‹จ ๋ชจ๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค (Polling)...\n");

    while (1) {
        /*
         * 2. ์ œ์–ด๊ถŒ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ (Immediate Return):
         * read() ํ˜ธ์ถœ ์‹œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋ฉด ์ปค๋„์€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ž ์žฌ์šฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
         * ๋Œ€์‹  EAGAIN ๋˜๋Š” EWOULDBLOCK ์—๋Ÿฌ๋ฅผ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ์ œ์–ด๊ถŒ์„ ๋Œ๋ ค์ค๋‹ˆ๋‹ค.
         */
        ssize_t bytes_read = read(sockfd, buffer, sizeof(buffer));

        if (bytes_read == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                /*
                 * 3. ๋ฐ”์œ ๋Œ€๊ธฐ (Busy Wait/Spinning):
                 * ๋ฐ์ดํ„ฐ๊ฐ€ ์•„์ง ๋„์ฐฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๋Š” ์—ฌ๊ธฐ์„œ ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  
                 * ๋‹ค๋ฅธ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜, ๋‹ค์‹œ ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ•  ์ค€๋น„๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.
                 * * ์ฃผ์˜: ์ด ๋ฃจํ”„๋Š” CPU ์‚ฌ์šฉ๋ฅ ์„ 100%๊นŒ์ง€
                 * ์น˜์†Ÿ๊ฒŒ ๋งŒ๋“ค๋ฉฐ ์œ ์ €/์ปค๋„ ๊ฒฝ๊ณ„๋ฅผ ์™•๋ณตํ•˜๋Š” ๋ชจ๋“œ ์ „ํ™˜ ๋น„์šฉ์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
                 */
                printf("๋ฐ์ดํ„ฐ ๋ฏธ๋„์ฐฉ. ๋‹ค๋ฅธ ์ž‘์—… ์ˆ˜ํ–‰ ์ค‘...\n");
                
                // ์‹ค์ œ ๊ณ ์„ฑ๋Šฅ ์„œ๋ฒ„๋ผ๋ฉด ์—ฌ๊ธฐ์„œ ๋‹ค๋ฅธ ์œ ์˜๋ฏธํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
                do_other_business_logic(); 
                
                continue; 
            }
            break; // ์‹ค์ œ ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๋ฃจํ”„ ์ข…๋ฃŒ
        }

        /*
         * 4. ๋ฐ์ดํ„ฐ ํš๋“:
         * ์—ฌ๋Ÿฌ ๋ฒˆ์˜ Polling ๋์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฒ„ํผ์— ์ฐจ๋Š” ์ˆœ๊ฐ„, 
         * ์‹œ์Šคํ…œ ์ฝœ์€ ๋น„๋กœ์†Œ ์œ ์˜๋ฏธํ•œ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
         */
        if (bytes_read > 0) {
            printf("์ˆ˜์‹  ์„ฑ๊ณต: %.*s\n", (int)bytes_read, buffer);
            break;
        }
    }
}

Non-Blocking ๋ชจ๋ธ์˜ ํšจ์œจ์  ์ž„๊ณ„์ 

Non-Blocking I/O๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ๊ฐ€ ์ˆ˜์ฒœ ๊ฐœ์˜ ์—ฐ๊ฒฐ์„ ๋™์‹œ์— ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์•„ํ‚คํ…์ฒ˜์  ๊ธฐ๋ฐ˜์„ ์ œ๊ณตํ•˜์ง€๋งŒ, Polling์˜ ๋ฐ€๋„๊ฐ€ ๋†’์•„์งˆ์ˆ˜๋ก CPU ํšจ์œจ์€ ๊ธ‰๊ฒฉํžˆ ํ•˜๋ฝํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ ์—”์ง€๋‹ˆ์–ด๋ง์—์„œ๋Š” ์ด๋ฅผ ๋‹จ๋…์œผ๋กœ ์“ฐ๊ธฐ๋ณด๋‹ค ์ปค๋„์ด ์ด๋ฒคํŠธ ๋ฐœ์ƒ์„ ์•Œ๋ ค์ฃผ๋Š” ๋ฉ€ํ‹ฐํ”Œ๋ ‰์‹ฑ ๊ธฐ์ˆ ๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ, CPU๊ฐ€ โ€˜์œ ์˜๋ฏธํ•œ ์‹ ํ˜ธโ€™๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์›€์ง์ด๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

๐Ÿงฉ Synchronous

Synchronous(๋™๊ธฐ) ๋ชจ๋ธ์€ โ€˜์ž‘์—…์˜ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ฃผ์ฒดโ€™๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ์ œ์–ด ํ๋ฆ„๊ณผ ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„์ด ์–ด๋–ป๊ฒŒ ๋งž๋ฌผ๋ฆฌ๋Š”์ง€์— ์ง‘์ค‘ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ชจ๋ธ์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ปค๋„์—๊ฒŒ ์š”์ฒญํ•œ ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ทธ ๊ฒฐ๊ณผ๊ฐ’์„ ์ง์ ‘ ์ฑ™๊ฒจ์•ผ ํ•  ์˜๋ฌด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ์ด๋“ค์ด Blocking๊ณผ Synchronous๋ฅผ ํ˜ผ๋™ํ•˜์ง€๋งŒ, ์ด ๋‘˜์€ ์—„๋ฐ€ํžˆ ๋‹ค๋ฅธ ์ธต์œ„์˜ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค๋Š” ์šด์˜์ฒด์ œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ช…๋ น์–ด์˜ ์ˆœ์ฐจ์  ์‹คํ–‰ ๋‹จ์œ„์ด๋ฉฐ, ๋™๊ธฐ ๋ชจ๋ธ์€ ์ด ์ˆœ์ฐจ์„ฑ์„ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ•์ œํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์„ค๋ น Non-Blocking ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ œ์–ด๊ถŒ์„ ์ฆ‰์‹œ ๋Œ๋ ค๋ฐ›์•˜๋‹ค ํ•˜๋”๋ผ๋„, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ๋ฐ์ดํ„ฐ๊ฐ€ ๋„์ฐฉํ–ˆ๋Š”์ง€ ์ง์ ‘ ํ™•์ธํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ด๋Š” ์—ฌ์ „ํžˆ ๋™๊ธฐ์‹ ํ๋ฆ„์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ํ๋ฆ„(Control Flow)๊ณผ ๋ฐ์ดํ„ฐ์˜ ์™„์„ฑ(Data Completion)์ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ”„๋กœ์„ธ์Šค ์ถ”์ƒํ™” ๊ด€์ ์—์„œ ๋™๊ธฐ ๋ชจ๋ธ์€ ์ธ๊ณผ๊ด€๊ณ„๊ฐ€ ๋ช…ํ™•ํ•œ ์ง๋ ฌ์  ์„ธ๊ณ„๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜๋ฉฐ, ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ๊ณผ์ •์ด ๋‹จ์ผํ•œ ์„ ํ˜•์  ํƒ€์ž„๋ผ์ธ ์œ„์— ๋†“์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋Š” ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๊ฐ•๋ ฅํ•œ ์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์‹œ์Šคํ…œ์˜ ์ „์ฒด ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๊ฐ€์žฅ ๋А๋ฆฐ ๊ตฌ์„ฑ ์š”์†Œ์ธ I/O ์žฅ์น˜์˜ ์„ฑ๋Šฅ์— ์ข…์†๋˜๋Š” ๋ณ‘๋ชฉ ํ˜„์ƒ์„ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค. CPU๊ฐ€ ์ดˆ๋‹น ์ˆ˜์‹ญ์–ต ๊ฐœ์˜ ๋ช…๋ น์–ด๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , ๋™๊ธฐ์  ๊ตฌ์กฐ ์•„๋ž˜์„œ๋Š” ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜์–ด ์œ ์ € ์˜์—ญ์œผ๋กœ ๋ณต์‚ฌ๋  ๋•Œ๊นŒ์ง€ ๋กœ์ง์˜ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‚˜์•„๊ฐ€์ง€ ๋ชปํ•˜๊ณ  ๋ฌถ์—ฌ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋…ผ๋ฆฌ์  ๋™๊ธฐํ™” ๊ณผ์ •, ์ฆ‰ ํ˜ธ์ถœ์ž๊ฐ€ ํ”ผํ˜ธ์ถœ์ž์˜ ์ƒํƒœ๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•˜๋ฉฐ ์ž‘์—…์˜ ์ข…๊ฒฐ์ ์„ ์Šค์Šค๋กœ ์ฐพ์•„๋‚ด๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์•„๋ž˜์˜ ์ฝ”๋“œ ๊ตฌ์กฐ์—์„œ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚ฉ๋‹ˆ๋‹ค. ์ œ์–ด๊ถŒ์„ ๋Œ๋ ค๋ฐ›๋Š” ํ–‰์œ„์™€ ๊ฒฐ๊ณผ๊ฐ’์„ ํ™•์ • ์ง“๋Š” ํ–‰์œ„ ์‚ฌ์ด์˜ ๊ฐ„๊ทน์„ ์–ด๋–ป๊ฒŒ ๋ฉ”์šฐ๋Š”์ง€๊ฐ€ ๋™๊ธฐ ๋ชจ๋ธ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
 * Synchronous ๋ชจ๋ธ์˜ ๋…ผ๋ฆฌ์  ํ๋ฆ„
 * * ๋™๊ธฐ ๋ชจ๋ธ์˜ ํ•ต์‹ฌ์€ '๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ฃผ์ฒด'๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž์‹ ์ด๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค.
 * ํ”„๋กœ์„ธ์Šค ์ถ”์ƒํ™” ๊ด€์ ์—์„œ ๋ณด๋ฉด, ์ด๋Š” ๋ช…๋ น์–ด์˜ ์ˆœ์ฐจ์  ์‹คํ–‰์„ 
 * ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ•์ œํ•˜์—ฌ ๋ฐ์ดํ„ฐ์˜ ์ •ํ•ฉ์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๊ฐ€์žฅ ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
 */
void synchronous_data_processing(int sockfd) {
    char buffer[1024];
    
    /* * 1. ์ž‘์—…์˜ ์š”์ฒญ๊ณผ ์ธ๊ณผ์  ๊ฒฐํ•ฉ:
     * ํ˜ธ์ถœ์ž๋Š” ์ปค๋„์— ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•œ ํ›„, ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ € ์˜์—ญ์˜ 
     * ๋ฉ”๋ชจ๋ฆฌ์— ์™„์ „ํžˆ ๋ณต์‚ฌ๋  ๋•Œ๊นŒ์ง€ ์ด ์ž‘์—…์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
     */
    printf("๋™๊ธฐ์  ๋ฐ์ดํ„ฐ ํš๋“ ์‹œ์ž‘...\n");

    /* * 2. Blocking-Sync vs Non-Blocking-Sync:
     * - Blocking-Sync: ์•„๋ž˜ read()์—์„œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž ๋“ค๋ฉฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆผ.
     * - Non-Blocking-Sync: EAGAIN์„ ๋ฐ›๋”๋ผ๋„ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ์ง์ ‘ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธ(Polling).
     * * ์–ด๋–ค ๊ฒฝ์šฐ๋“  '๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๊ณ  ํ™•์ • ์ง“๋Š” ์ฃผ์ฒด'๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋ฏ€๋กœ 
     * ์ด๋Š” ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋™๊ธฐ(Synchronous) ์ž‘์—…์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
     */
    ssize_t result = read(sockfd, buffer, sizeof(buffer));

    /* * 3. ๊ฒฐ๊ณผ์˜ ์ฆ‰๊ฐ์  ์ฒ˜๋ฆฌ:
     * ์ปค๋„๋กœ๋ถ€ํ„ฐ ์ œ์–ด๊ถŒ๊ณผ ํ•จ๊ป˜ '์™„์„ฑ๋œ ๋ฐ์ดํ„ฐ'๋ฅผ ๋„˜๊ฒจ๋ฐ›๋Š” ์ˆœ๊ฐ„ 
     * ๋‹ค์Œ ๋กœ์ง์œผ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค์˜ ์„ ํ˜•์  ํƒ€์ž„๋ผ์ธ์ด ์œ ์ง€๋˜๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค.
     */
    if (result > 0) {
        process_received_data(buffer, result);
    }
    
    // ์ž‘์—…์ด ์™„์ „ํžˆ ๋๋‚œ ํ›„์—์•ผ ๋‹ค์Œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
    printf("๋™๊ธฐ์  ์ž‘์—… ์ข…๊ฒฐ. ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.\n");
    proceed_to_next_step();
}

๋™๊ธฐ ๋ชจ๋ธ์—์„œ์˜ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๋Š” ์ปค๋„ ์ŠคํŽ˜์ด์Šค์™€ ์œ ์ € ์ŠคํŽ˜์ด์Šค ์‚ฌ์ด์˜ ์—„๊ฒฉํ•œ ๊ฒฝ๊ณ„์„ ์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ์ปค๋„์ด ํ•˜๋“œ์›จ์–ด๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ์ž์‹ ์˜ ๋ฒ„ํผ๋ฅผ ์ฑ„์šฐ๋Š” ๋™์•ˆ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ โ€˜๊ฒฐ๊ณผโ€™๋ผ๋Š” ์ƒํƒœ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๋Œ€๊ธฐํ•˜๊ฑฐ๋‚˜ ์ฃผ๊ธฐ์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. CPU์™€ RAM์€ ๋งˆ๋”๋ณด๋“œ๋ฅผ ํ†ตํ•ด ๊ธด๋ฐ€ํžˆ ์—ฐ๊ฒฐ๋˜์–ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์ง€๋งŒ, ๋™๊ธฐ์‹ I/O์—์„œ๋Š” ์ด ๋ฌผ๋ฆฌ์  ์†๋„๋ณด๋‹ค ์ปค๋„์˜ ์ž‘์—… ์™„๋ฃŒ ํ†ต์ง€๊ฐ€ ์šฐ์„ ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์ปค๋„ ๋ฒ„ํผ์—์„œ ์œ ์ € ๋ฉ”๋ชจ๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๊ฐ€ ์™„๋ฃŒ๋˜๋Š” ์‹œ์ ์ด ๊ณง ๋™๊ธฐ์  ์ž‘์—…์˜ ์ข…๊ฒฐ์ ์ด ๋ฉ๋‹ˆ๋‹ค.

๋™๊ธฐ์‹ ์ฒ˜๋ฆฌ์˜ ๊ตฌ์กฐ์  ์•ˆ์ •์„ฑ ย  ๋™๊ธฐ ๋ชจ๋ธ์€ ํ˜ธ์ถœ์ž์™€ ํ”ผํ˜ธ์ถœ์ž ์‚ฌ์ด์˜ ์ƒํƒœ๊ฐ€ ํ•ญ์ƒ ์ผ์น˜ํ•จ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ณต์žกํ•œ ๋ถ„์‚ฐ ์‹œ์Šคํ…œ์ด๋‚˜ ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” โ€˜์ƒํƒœ ๋ถˆ์ผ์น˜โ€™ ๋ฌธ์ œ๋ฅผ ์›์ฒœ ์ฐจ๋‹จํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ์˜ ์ˆœ์ฐจ์  ์ •ํ•ฉ์„ฑ์ด ๋ฌด์—‡๋ณด๋‹ค ์ค‘์š”ํ•œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ์˜์—ญ์—์„œ ์‹œ์Šคํ…œ์˜ ๋ณต์žก๋„๋ฅผ ๋‚ฎ์ถ”๊ณ  ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๊ฒฐ์ •์ ์ธ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿงฉ Asynchronous

Asynchronous(๋น„๋™๊ธฐ) ๋ชจ๋ธ์€ โ€˜๊ด€์‹ฌ์˜ ์™„์ „ํ•œ ๋ถ„๋ฆฌโ€™๋ฅผ ํ†ตํ•ด I/O ์ง€์—ฐ์˜ ๊ตด๋ ˆ๋ฅผ ๋ฒ—์–ด๋˜์ง‘๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ปค๋„์— I/O ์ž‘์—…์„ ์š”์ฒญํ•จ๊ณผ ๋™์‹œ์— ๊ทธ ์ž‘์—…์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ถŒํ•œ๊ณผ ์ฑ…์ž„์„ ๋„˜๊น๋‹ˆ๋‹ค. โ€œ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜๋ฉด ๋‚˜๋ฅผ ๊นจ์šฐ๊ฑฐ๋‚˜, ๋‚ด ๋ฉ”๋ชจ๋ฆฌ์— ์ง์ ‘ ๋„ฃ์–ด๋‹ฌ๋ผโ€๋Š” ๊ณ„์•ฝ์„ ๋งบ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ง„์ •ํ•œ ๋น„๋™๊ธฐ ๋ชจ๋ธ์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ I/O ์ž‘์—…์ด ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ์ž์‹ ์˜ ๋ณธ๋ž˜ ์—…๋ฌด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์ปค๋„์ด ๋ฐฐ๊ฒฝ(Background)์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์ฑ„์šด ๋’ค ํ†ต์ง€(Notification)๋ฅผ ๋ณด๋‚ด๋Š” ์‹œ์ ์—๋งŒ ๋ฐ˜์‘ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” CPU๊ฐ€ ์œ ํœด ์ƒํƒœ๋กœ ๋‚ญ๋น„๋˜๋Š” ์‹œ๊ฐ„์„ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ œ๊ฑฐํ•˜๋ ค๋Š” ์—”์ง€๋‹ˆ์–ด๋ง์˜ ์ •์ˆ˜์ž…๋‹ˆ๋‹ค.

์ด ๋ชจ๋ธ์˜ ์ •์ˆ˜๋Š” ์ปค๋„์ด ์œ ์ € ์ŠคํŽ˜์ด์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์จ์ฃผ๋Š” โ€˜Proactorโ€™ ํŒจํ„ด์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ ๋™๊ธฐ ๋ฐฉ์‹์ด โ€œ๋ฐ์ดํ„ฐ๊ฐ€ ์™”์œผ๋‹ˆ ๊ฐ€์ ธ๊ฐ€๋ผโ€๊ณ  ์•Œ๋ ค์ฃผ๋Š” ์ˆ˜๋™์  ํ†ต์ง€์˜€๋‹ค๋ฉด, ๋น„๋™๊ธฐ๋Š” โ€œ๋„ˆ์˜ ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ด๋ฏธ ๋‹ค ์ฑ„์›Œ๋‘์—ˆ์œผ๋‹ˆ ๋ฐ”๋กœ ์“ฐ๊ธฐ๋งŒ ํ•ด๋ผโ€๊ณ  ํ™•์–ธํ•ฉ๋‹ˆ๋‹ค. CPU์™€ RAM ์‚ฌ์ด์˜ ๊ธด๋ฐ€ํ•œ ํ˜‘๋ ฅ์„ ๊ฐ€์žฅ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์œ ์ € ์ŠคํŽ˜์ด์Šค์—์„œ์˜ ์ถ”๊ฐ€์ ์ธ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ ๋น„์šฉ์„ ๊ทน๋‹จ์ ์œผ๋กœ ๋‚ฎ์ถ”๋ฉฐ, ๋ฆฌ๋ˆ…์Šค์˜ io_uring์ด๋‚˜ ์œˆ๋„์šฐ์˜ IOCP ๊ฐ™์€ ๊ธฐ์ˆ ๋“ค์ด ์ง€ํ–ฅํ•˜๋Š” ๊ถ๊ทน์ ์ธ I/O ํšจ์œจ์„ฑ์„ ์ƒ์ง•ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ œ์–ด์˜ ์—ญ์ „, ์ฆ‰ ์š”์ฒญ ์‹œ์ ๊ณผ ์™„๋ฃŒ ํ†ต์ง€ ์‹œ์ ์ด ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์–ด ์‹คํ–‰ ํ๋ฆ„์ด ํŒŒํŽธํ™”๋˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์•„๋ž˜์˜ ์ฝ”๋“œ ๊ตฌ์กฐ ์†์— ์ƒ์„ธํžˆ ๋ฌ˜์‚ฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ ์ฝœ์ด ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ์„ ๋„˜์–ด, ์ž‘์—…์˜ ์ข…๊ฒฐ ์ฃผ์ฒด๊ฐ€ ์ปค๋„๋กœ ๋„˜์–ด๊ฐ€๋Š” ๊ณผ์ •์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <aio.h>

/**
 * Asynchronous I/O ์ธํ„ฐํŽ˜์ด์Šค ๋ชจ๋ธ
 * * ๋น„๋™๊ธฐ ๋ชจ๋ธ์˜ ํ•ต์‹ฌ์€ '๊ถŒํ•œ๊ณผ ์ฑ…์ž„์˜ ์ „์ ์ธ ์ด์–‘'์ž…๋‹ˆ๋‹ค.
 * ์ด๋Š” CPU๊ฐ€ I/O ์žฅ์น˜์˜ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” 
 * 0.1%์˜ ์‹œ๊ฐ„์กฐ์ฐจ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ณ  ์˜ค์ง ์—ฐ์‚ฐ์—๋งŒ ๋ชฐ์ž…ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
 */
void asynchronous_io_handler(sigval_t sig) {
    struct aiocb *cbp = (struct aiocb *)sig.sival_ptr;

    // 4. ์™„๋ฃŒ ํ†ต์ง€ ๋ฐ ์ฒ˜๋ฆฌ (Callback/Notification):
    // ์ปค๋„์ด ์œ ์ € ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ์ฑ„์šด ๋’ค์—์•ผ ๋น„๋กœ์†Œ ์ด ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    if (aio_error(cbp) == 0) {
        ssize_t n = aio_return(cbp);
        printf("\n[ํ†ต์ง€] ๋น„๋™๊ธฐ ์ฝ๊ธฐ ์™„๋ฃŒ: %.*s\n", (int)n, (char *)cbp->aio_buf);
    }
}

void start_asynchronous_read(int sockfd) {
    struct aiocb cb;
    char buffer[1024];

    memset(&cb, 0, sizeof(struct aiocb));
    cb.aio_fildes = sockfd;
    cb.aio_buf = buffer;
    cb.aio_nbytes = sizeof(buffer);
    
    // 1. ํ†ต์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์„ค์ •:
    // ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜๋ฉด ํ˜ธ์ถœ๋  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    cb.aio_sigevent.sigev_notify = SIGEV_THREAD;
    cb.aio_sigevent.sigev_notify_function = asynchronous_io_handler;
    cb.aio_sigevent.sigev_value.sival_ptr = &cb;

    /*
     * 2. ์ž‘์—… ์š”์ฒญ ๋ฐ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ (Request Submission):
     * aio_read()๋Š” ์ปค๋„์—๊ฒŒ '๋‚˜์ค‘์— ์ฝ์–ด์„œ ๋‚ด ๋ฉ”๋ชจ๋ฆฌ์— ๋„ฃ์–ด๋‹ฌ๋ผ'๊ณ  
     * ๋ช…๋ น๋งŒ ๋‚ด๋ฆฐ ๋’ค 0.0001์ดˆ ๋งŒ์— ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
     */
    if (aio_read(&cb) == -1) {
        perror("aio_read ์‹คํŒจ");
        return;
    }

    /*
     * 3. ๋…๋ฆฝ์  ์—…๋ฌด ์ˆ˜ํ–‰ (Non-dependent Execution):
     * ํ”„๋กœ์„ธ์Šค์˜ 'Running' ์ƒํƒœ๋ฅผ 100% ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.
     * I/O๊ฐ€ ๋ฐฐ๊ฒฝ์—์„œ ๋Œ์•„๊ฐ€๋Š” ๋™์•ˆ, ๋ฉ”์ธ ๋กœ์ง์€ ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  ์—ฐ์‚ฐ์„ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.
     */
    for (int i = 0; i < 5; i++) {
        printf("๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š” ๋‹ค๋ฅธ ์—ฐ์‚ฐ ์ค‘... [%d]\n", i);
        sleep(1); 
    }
}

๊ทธ๋Ÿฌ๋‚˜ ๋น„๋™๊ธฐ ๋ชจ๋ธ์€ โ€˜์ธ์ง€์  ๋ถ€ํ•˜โ€™๋ผ๋Š” ๋†’์€ ์ฒญ๊ตฌ์„œ๋ฅผ ๋‚ด๋ฐ‰๋‹ˆ๋‹ค. ์ž‘์—…์˜ ์š”์ฒญ๊ณผ ์™„๋ฃŒ๊ฐ€ ์‹œ๊ฐ„์ ์œผ๋กœ ๊ฒฉ๋ฆฌ๋˜๋ฉด์„œ ํ”„๋กœ๊ทธ๋žจ์˜ ๋…ผ๋ฆฌ์  ์„ ํ›„ ๊ด€๊ณ„๊ฐ€ ๋’ค์„ž์ด๊ฒŒ ๋˜๊ณ , ์ด๋Š” ์Šคํƒ ์ถ”์ (Stack Trace)์˜ ๋‹จ์ ˆ๋กœ ์ด์–ด์ ธ ๋””๋ฒ„๊น…์„ ๋ฏธ๋กœ ์†์— ๊ฐ€๋‘ก๋‹ˆ๋‹ค. ๋ฌ˜์‚ฌํ•œ ์ผ๊ด€๋œ ํ”„๋กœ์„ธ์Šค์˜ ํ๋ฆ„์ด ๋น„๋™๊ธฐ ์„ธ๊ณ„์—์„œ๋Š” ์ˆ˜๋งŽ์€ ์ฝœ๋ฐฑ๊ณผ ์ด๋ฒคํŠธ์˜ ํŒŒํŽธ์œผ๋กœ ํฉ์–ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—”์ง€๋‹ˆ์–ด๋Š” ํฉ์–ด์ง„ ํŒŒํŽธ๋“ค์„ ๋ชจ์•„ ํ•˜๋‚˜์˜ ๋น„์ฆˆ๋‹ˆ์Šค ์ปจํ…์ŠคํŠธ๋กœ ์—ฎ์–ด๋‚ด๊ธฐ ์œ„ํ•œ ์ •๊ตํ•œ ์ƒํƒœ ๋จธ์‹ (State Machine)์„ ๊ตฌ์ถ•ํ•ด์•ผ ํ•˜๋Š” ๊ณผ์ œ๋ฅผ ๋– ์•ˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ ๋ชจ๋ธ์˜ ๋„์ž… ๋น„์šฉ๊ณผ ๊ฐ€์น˜

๋น„๋™๊ธฐ I/O๋Š” ์ปค๋„์˜ ์ž ์žฌ๋ ฅ์„ ๊ทนํ•œ๊นŒ์ง€ ๋Œ์–ด์˜ฌ๋ ค ์ตœ์†Œํ•œ์˜ ์ž์›์œผ๋กœ ์ˆ˜๋งŒ ๊ฑด์˜ ๋™์‹œ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅ์ผ€ ํ•˜์ง€๋งŒ, ์„ค๊ณ„์˜ ๋ณต์žก๋„์™€ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ ์—ญ์‹œ ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ƒ์Šนํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์„ฑ๋Šฅ ์ˆ˜์น˜์— ๋งค๋ชฐ๋˜๊ธฐ๋ณด๋‹ค, ์‹œ์Šคํ…œ์˜ ๊ทœ๋ชจ์™€ ํŒ€์˜ ์ˆ™๋ จ๋„, ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น OS ํ™˜๊ฒฝ์ด ์ œ๊ณตํ•˜๋Š” ๋น„๋™๊ธฐ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ์˜ ์„ฑ์ˆ™๋„๋ฅผ ๋ฉด๋ฐ€ํžˆ ๊ฒ€ํ† ํ•˜์—ฌ ๋„์ž… ์‹ค์ต์„ ๋”ฐ์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Linux epoll

ํ˜„๋Œ€ ๊ณ ์„ฑ๋Šฅ ์„œ๋ฒ„์˜ ์—ญ์‚ฌ๋Š” โ€˜C10K ๋ฌธ์ œ(๋งŒ ๊ฐœ์˜ ํด๋ผ์ด์–ธํŠธ ๋™์‹œ ์ ‘์†)โ€™๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ๊ฒƒ์ธ๊ฐ€์— ๋Œ€ํ•œ ํˆฌ์Ÿ์˜ ๊ธฐ๋ก์ž…๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์˜ select์™€ poll์ด ๊ฐ€์กŒ๋˜ ๊ทผ๋ณธ์ ์ธ ํ•œ๊ณ„๋Š” ๊ฐ์‹œ ๋Œ€์ƒ์ธ ์†Œ์ผ“์˜ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์„ฑ๋Šฅ์ด ์„ ํ˜•์ ์œผ๋กœ ํ•˜๋ฝ($O(N)$)ํ•œ๋‹ค๋Š” ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์šด์˜์ฒด์ œ๋Š” ํ•˜๋“œ์›จ์–ด ์ž์›์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ, ๋งค๋ฒˆ ์ˆ˜๋งŒ ๊ฐœ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ปค๋„๋กœ ๋ณต์‚ฌํ•˜๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ํ›‘์–ด์•ผ ํ•˜๋Š” ๋ฐฉ์‹์€ CPU ์—ฐ์‚ฐ ์ž์›์˜ ๋‚ญ๋น„๋ฅผ ๋„˜์–ด ์‹œ์Šคํ…œ ์ „์ฒด์˜ ์‘๋‹ต ์ง€์—ฐ์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋น„ํšจ์œจ์„ ํƒ€ํŒŒํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•œ ๋ฆฌ๋ˆ…์Šค์˜ epoll์€ ๊ด€์ ์„ ์™„์ „ํžˆ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ โ€˜์ƒํƒœ์˜ ๋“ฑ๋กโ€™๊ณผ โ€˜์ด๋ฒคํŠธ์˜ ํ†ต์ง€โ€™๋กœ ๋ถ„๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํŠน์ง•select / pollepoll
์‹œ๊ฐ„ ๋ณต์žก๋„$O(N)$ (์ „์ฒด ๋ฃจํ”„ ํƒ์ƒ‰)$O(1)$ (์ด๋ฒคํŠธ ๋ฐœ์ƒ ๊ฑด๋งŒ ์ฒ˜๋ฆฌ)
๊ด€์‹ฌ ๋ฆฌ์ŠคํŠธ ๊ด€๋ฆฌ๋งค๋ฒˆ ์œ ์ € โ†” ์ปค๋„ ๋ณต์‚ฌ์ปค๋„ ๋‚ด๋ถ€(Red-Black Tree)์—์„œ ๊ด€๋ฆฌ
์ตœ๋Œ€ ์†Œ์ผ“ ์ˆ˜FD_SETSIZE ์ œํ•œ (๊ธฐ๋ณธ 1024)์ œํ•œ ์—†์Œ (์‹œ์Šคํ…œ ์ž์› ํ—ˆ์šฉ์น˜๊นŒ์ง€)
์•Œ๋ฆผ ๋ฐฉ์‹โ€œ์–ด๋”˜๊ฐ€ ๋ฐ์ดํ„ฐ ์™”์œผ๋‹ˆ ๋„ˆ๊ฐ€ ์ฐพ์•„๋ดโ€โ€œ์ด ์†Œ์ผ“๋“ค์— ๋ฐ์ดํ„ฐ ์™”์œผ๋‹ˆ ๊ฐ€์ ธ๊ฐ€โ€

epoll์€ ์ปค๋„ ๋‚ด๋ถ€์— ๋ ˆ๋“œ-๋ธ”๋ž™ ํŠธ๋ฆฌ(Red-Black Tree)๋ฅผ ๊ตฌ์ถ•ํ•˜์—ฌ ๊ฐ์‹œ ๋Œ€์ƒ ์†Œ์ผ“์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์†Œ์ผ“ ํ•˜๋‚˜๊ฐ€ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋  ๋•Œ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ๋น ๋ฅด๊ฒŒ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ๋„์ฐฉํ•œ ์†Œ์ผ“๋“ค๋งŒ ๋ณ„๋„์˜ Ready List(๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ)์— ๋‹ด์Šต๋‹ˆ๋‹ค. CPU์™€ RAM ์‚ฌ์ด์˜ ๊ธด๋ฐ€ํ•œ ํ˜‘๋ ฅ์€ ์—ฌ๊ธฐ์„œ ๋น›์„ ๋ฐœํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋“œ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ปค๋„์€ ์ธํ„ฐ๋ŸฝํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ†ตํ•ด Ready List์— ํ•ด๋‹น ์†Œ์ผ“์„ ์ฆ‰์‹œ ์ง‘์–ด๋„ฃ๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ด ๋ฆฌ์ŠคํŠธ๋งŒ ์ฝ์–ด ๊ฐ€๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์—”์ง€๋‹ˆ์–ด๊ฐ€ ๋ฐ˜๋“œ์‹œ ๊ฒฐ์ •ํ•ด์•ผ ํ•  ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๋Š” Trigger ๋ฐฉ์‹์˜ ์„ ํƒ์ž…๋‹ˆ๋‹ค.

  • Level-Triggered (LT): ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฒ„ํผ์— ๋‚จ์•„ ์žˆ๋Š” ๋™์•ˆ ๊ณ„์† ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. select์™€ ์œ ์‚ฌํ•˜์—ฌ ๊ตฌํ˜„์ด ์‰ฝ์ง€๋งŒ, ๋ถˆํ•„์š”ํ•œ ์ด๋ฒคํŠธ ํ˜ธ์ถœ์ด ์žฆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Edge-Triggered (ET): ๋ฐ์ดํ„ฐ๊ฐ€ ์ฒ˜์Œ ๋„์ฐฉํ•œ โ€˜๋ณ€ํ™”์˜ ์ˆœ๊ฐ„โ€™์—๋งŒ ๋”ฑ ํ•œ ๋ฒˆ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. Non-Blocking ์†Œ์ผ“๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ CPU ์œ ํœด ์‹œ๊ฐ„์„ ๊ทนํ•œ์œผ๋กœ ์ฅ์–ด์งค ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ฒ„ํผ๋ฅผ ์™„์ „ํžˆ ๋น„์šฐ์ง€ ์•Š์œผ๋ฉด ์˜์˜ ํ†ต์ง€๋ฅผ ๋ฐ›์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜์ด ์žˆ์–ด ์ •๊ตํ•œ ์„ค๊ณ„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

/**
 * Linux epoll์„ ํ™œ์šฉํ•œ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ตฌํ˜„
 * * epoll์˜ ํ•ต์‹ฌ์€ '๊ด€์‹ฌ์˜ ๋“ฑ๋ก'๊ณผ 'ํ†ต์ง€์˜ ์ˆ˜์‹ '์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐ ์žˆ์Šต๋‹ˆ๋‹ค.
 * ์šด์˜์ฒด์ œ๋Š” ํ•˜๋“œ์›จ์–ด ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด 
 * ํ”„๋กœ์„ธ์Šค ์ƒํƒœ ์ „์ด๋ฅผ ์ œ์–ดํ•˜๋ฉฐ, epoll์€ ์ด ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” 
 * ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ๊ณผ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ ๋น„์šฉ์„ ๊ทนํ•œ์œผ๋กœ ์ ˆ๊ฐํ•ฉ๋‹ˆ๋‹ค.
 */
void run_epoll_event_loop(int server_fd) {
    // 1. epoll ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    // ์ปค๋„ ๋‚ด๋ถ€์— ์ด๋ฒคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ „์šฉ ๊ณต๊ฐ„(๋ ˆ๋“œ-๋ธ”๋ž™ ํŠธ๋ฆฌ)์„ ๋งˆ๋ จํ•ฉ๋‹ˆ๋‹ค.
    int epfd = epoll_create1(0);
    struct epoll_event ev, events[MAX_EVENTS];

    // 2. ์—ฃ์ง€ ํŠธ๋ฆฌ๊ฑฐ(Edge-Triggered) ๋ฐ Non-Blocking ์„ค์ •
    // ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚˜๋Š” '์ˆœ๊ฐ„'์—๋งŒ ํ†ต์ง€๋ฐ›์•„ ์‹œ์Šคํ…œ ์ฝœ ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.
    set_nonblocking(server_fd);
    ev.events = EPOLLIN | EPOLLET; 
    ev.data.fd = server_fd;

    // 3. ๊ด€์‹ฌ ๋ฆฌ์ŠคํŠธ ๋“ฑ๋ก (epoll_ctl)
    // ์ปค๋„ ๋‚ด๋ถ€ ํŠธ๋ฆฌ ๊ตฌ์กฐ์— ์†Œ์ผ“์„ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์†Œ์ผ“ ์ƒํƒœ ๋ณ€๊ฒฝ์€ 
    // ์ปค๋„์ด ์ง์ ‘ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ๋งค๋ฒˆ ์ „์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
    epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, &ev);

    while (1) {
        /**
         * 4. ์ด๋ฒคํŠธ ๋Œ€๊ธฐ (epoll_wait)
         * ํ”„๋กœ์„ธ์Šค๋Š” Ready List์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ฐฐ ๋•Œ๊นŒ์ง€ ํšจ์œจ์ ์œผ๋กœ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค.
         * CPU๋Š” ์ด ๊ธฐ๊ฐ„ ๋™์•ˆ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, 
         * Ready List์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์˜ค๋Š” ์ˆœ๊ฐ„ $O(1)$์˜ ์†๋„๋กœ ์ฆ‰์‹œ ๊นจ์–ด๋‚ฉ๋‹ˆ๋‹ค.
         */
        int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);

        for (int n = 0; n < nfds; ++n) {
            if (events[n].data.fd == server_fd) {
                // ์ƒˆ๋กœ์šด ์—ฐ๊ฒฐ ์ˆ˜๋ฝ ๋กœ์ง
                accept_new_connection(epfd, server_fd);
            } else {
                // ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ ๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ˆ˜ํ–‰
                handle_client_data(events[n].data.fd);
            }
        }
    }
}

epoll์ด ๋‹ฌ์„ฑํ•œ ๊ธฐ์ˆ ์  ๋„์•ฝ

epoll์€ ๋‹จ์ˆœํžˆ ์†๋„๋ฅผ ๋†’์ธ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์œ ์ € ์ŠคํŽ˜์ด์Šค์™€ ์ปค๋„ ์ŠคํŽ˜์ด์Šค ์‚ฌ์ด์˜ โ€˜๋ถˆํ•„์š”ํ•œ ๋Œ€ํ™”โ€™๋ฅผ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์€ ๋น„์‹ผ ๋น„์šฉ์„ ์น˜๋ฅด๋Š”๋ฐ, epoll์€ ์†Œ์ผ“ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ์Šค์œ„์นญ ํšŸ์ˆ˜์™€ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๋Ÿ‰์„ ์ตœ์†Œํ™”ํ•จ์œผ๋กœ์จ ํ•˜๋“œ์›จ์–ด ์„ฑ๋Šฅ์„ ์†Œํ”„ํŠธ์›จ์–ด ์ˆ˜์ค€์—์„œ ์˜จ์ „ํžˆ ๋ˆ„๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

Java NIO

Java ์—”์ง€๋‹ˆ์–ด์—๊ฒŒ Linux์˜ epoll์€ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ๋‹ค๋ฃจ๊ธฐ ๊นŒ๋‹ค๋กœ์šด ์›์‹œ ๋„๊ตฌ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. Java NIO(New I/O)๋Š” ์ด ๊ฑฐ์นœ ์ปค๋„์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์„ธ๊ณ„๋กœ ๋Œ์–ด์˜ฌ๋ ค, ๋‹จ์ผ ์Šค๋ ˆ๋“œ๊ฐ€ ์ˆ˜์ฒœ ๊ฐœ์˜ ์—ฐ๊ฒฐ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Selector, Channel, Buffer๋ผ๋Š” ์‚ผ๊ฐ ํŽธ๋Œ€์˜ ์ถ”์ƒํ™”๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์šด์˜์ฒด์ œ๋Š” ํ•˜๋“œ์›จ์–ด ์ž์›์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ์ œ๊ณตํ•˜๋ฉฐ, Java NIO๋Š” ๋ฐ”๋กœ ์ด ์ง€์ ์—์„œ ์ปค๋„์˜ ์„ฑ๋Šฅ์„ ์ž๋ฐ” ๊ฐ€์ƒ ๋จธ์‹ (JVM) ์œ„์—์„œ ์˜จ์ „ํžˆ ๊ตฌํ˜„ํ•ด๋ƒ…๋‹ˆ๋‹ค.

Java NIO์˜ ์ •์ˆ˜๋Š” Selector์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Linux epoll์˜ ์ž๋ฐ”ํŒ ๋ž˜ํผ(Wrapper)๋กœ, ์ˆ˜๋งŽ์€ Channel๋“ค ์ค‘ I/O ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ๋“ค๋งŒ ๊ณจ๋ผ๋‚ด๋Š” ๋ฉ€ํ‹ฐํ”Œ๋ ‰์„œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ Blocking I/O ๋ฐฉ์‹์ด โ€˜์—ฐ๊ฒฐ๋‹น ์Šค๋ ˆ๋“œ ํ•˜๋‚˜โ€™๋ฅผ ์†Œ๋ชจํ•˜๋ฉฐ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ–ˆ๋‹ค๋ฉด, NIO๋Š” ๋‹จ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ์œผ๋กœ ์ˆ˜๋งŒ ๊ฐœ์˜ ์†Œ์ผ“์„ ๊ฐ์‹œํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ์˜ ์ด๋™ ์—ญ์‹œ ํ˜์‹ ์ ์ž…๋‹ˆ๋‹ค. Java NIO๋Š” Direct Buffer๋ฅผ ํ†ตํ•ด โ€˜Zero-copyโ€™์— ๊ฐ€๊นŒ์šด ์„ฑ๋Šฅ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋Š” ํ•˜๋“œ์›จ์–ด์—์„œ ์ปค๋„ ๋ฒ„ํผ๋กœ, ๋‹ค์‹œ JVM ํž™ ๋ฉ”๋ชจ๋ฆฌ๋กœ ๋ณต์‚ฌ๋˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜์ง€๋งŒ, Direct Buffer๋Š” JVM ํž™์„ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์ปค๋„ ๋ฉ”๋ชจ๋ฆฌ์™€ ์ง์ ‘ ์†Œํ†ตํ•ฉ๋‹ˆ๋‹ค. CPU์™€ RAM ์‚ฌ์ด์˜ ๋งˆ๋”๋ณด๋“œ ํ†ต๋กœ๋ฅผ ๊ฐ€์žฅ ์งง์€ ๊ฒฝ๋กœ๋กœ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * Java NIO Selector๋ฅผ ์ด์šฉํ•œ ๋น„์ฐจ๋‹จ ์„œ๋ฒ„ ๋ฃจํ”„
 * * Java NIO๋Š” Linux์˜ epoll๊ณผ ๊ฐ™์€ ์ €์ˆ˜์ค€ ์ปค๋„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ์ฒด์ง€ํ–ฅ์ ์œผ๋กœ ์ถ”์ƒํ™”ํ•ฉ๋‹ˆ๋‹ค.
 * ์ด๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ๊ฐ€ ์ˆ˜์ฒœ ๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค/์Šค๋ ˆ๋“œ๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ
 * ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ฒŒ ํ•˜๋Š” '๋ฉ€ํ‹ฐํ”Œ๋ ‰์‹ฑ'์˜ ์ •์ˆ˜์ž…๋‹ˆ๋‹ค.
 */
public class NioServer {
    public void startServer() throws IOException {
        // 1. Selector ๋ฐ ServerSocketChannel ์˜คํ”ˆ
        // Selector๋Š” ์ปค๋„์˜ epoll ์ธ์Šคํ„ด์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ž๋ฐ” ์ธก ๋Œ€๋ฆฌ์ธ์ž…๋‹ˆ๋‹ค.
        Selector selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress("localhost", 8080));
        
        // 2. ๋น„์ฐจ๋‹จ(Non-blocking) ์„ค์ •
        // ์ด ์„ค์ •์ด ์žˆ์–ด์•ผ๋งŒ Selector๊ฐ€ ์—ฌ๋Ÿฌ ์ฑ„๋„์„ ๋™์‹œ์— ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
        serverSocket.configureBlocking(false);

        // 3. ๊ด€์‹ฌ ์ด๋ฒคํŠธ ๋“ฑ๋ก (ACCEPT)
        // ์ปค๋„์˜ ๊ด€์‹ฌ ๋ฆฌ์ŠคํŠธ(Red-Black Tree)์— ์ด ์„œ๋ฒ„ ์†Œ์ผ“์„ ๋“ฑ๋กํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("NIO ์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์‹œํ•ฉ๋‹ˆ๋‹ค...");

        while (true) {
            /**
             * 4. ์ด๋ฒคํŠธ ๊ฐ์‹œ (select)
             * ์ด ์ง€์ ์—์„œ ์Šค๋ ˆ๋“œ๋Š” Ready List์— ์‹ ํ˜ธ๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•˜๋ฉฐ CPU ์ž์›์„ ๋ฐ˜๋‚ฉํ•ฉ๋‹ˆ๋‹ค.
             */
            selector.select(); 

            // 5. ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ(SelectionKey) ์„ธํŠธ ํš๋“
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iter = selectedKeys.iterator();

            while (iter.hasNext()) {
                SelectionKey key = iter.next();

                if (key.isAcceptable()) {
                    // ์‹ ๊ทœ ์—ฐ๊ฒฐ ์ˆ˜๋ฝ ๋ฐ ๋น„์ฐจ๋‹จ ๋“ฑ๋ก
                    registerClient(selector, serverSocket);
                } else if (key.isReadable()) {
                    // ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ ์ˆ˜ํ–‰
                    // Direct Buffer ๋“ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด
                    // ์œ ์ €/์ปค๋„ ์‚ฌ์ด์˜ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ ๋น„์šฉ์„ 'Zero-copy'์— ๊ฐ€๊น๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
                    readData(key);
                }
                iter.remove(); // ์ฒ˜๋ฆฌํ•œ ์ด๋ฒคํŠธ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์ œ๊ฑฐ
            }
        }
    }

    private void registerClient(Selector selector, ServerSocketChannel serverSocket) throws IOException {
        SocketChannel client = serverSocket.accept();
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_READ);
    }

    private void readData(SelectionKey key) throws IOException {
        SocketChannel client = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int bytesRead = client.read(buffer);

        if (bytesRead == -1) {
            client.close();
        } else {
            // ๊ณ ํŠธ๋ž˜ํ”ฝ ํ™˜๊ฒฝ์—์„œ๋Š” ์ด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ๋ณ„๋„์˜ ์›Œ์ปค ์Šค๋ ˆ๋“œ ํ’€๋กœ ๋„˜๊ฒจ 
            // Selector ์Šค๋ ˆ๋“œ์˜ ์ง€์—ฐ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๊ณ ์„ฑ๋Šฅ ์•„ํ‚คํ…์ฒ˜์˜ ์ •์„์ž…๋‹ˆ๋‹ค.
            buffer.flip();
            System.out.println("๋ฐ์ดํ„ฐ ์ˆ˜์‹ : " + new String(buffer.array()).trim());
        }
    }
}

๊ณ ์„ฑ๋Šฅ ์ถ”์ƒํ™” ์ด๋ฉด์— ์ˆจ๊ฒจ์ง„ ์ œ์–ด์˜ ๋ณต์žก์„ฑ

Java NIO๋Š” ์„ฑ๋Šฅ ๋ฉด์—์„œ ์••๋„์ ์ด์ง€๋งŒ, ๋ฒ„ํผ์˜ flip(), clear() ์ฒ˜๋ฆฌ๋‚˜ ์†Œ์ผ“์˜ ์ƒํƒœ ๊ด€๋ฆฌ ๋“ฑ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ ๊ฒฝ ์จ์•ผ ํ•  ์ €์ˆ˜์ค€์˜ ๋ณต์žก๋„๊ฐ€ ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ์‹ค์ œ ํ˜„์—…์—์„œ๋Š” NIO๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๊ธฐ๋ณด๋‹ค, ์ด๋ฅผ ํ•œ ๋‹จ๊ณ„ ๋” ์šฐ์•„ํ•˜๊ฒŒ ๊ฐ์‹ธ ์•ˆ์€ Netty ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Reactor ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ๊ธฐ์ˆ ์˜ ์„ ํƒ์€ โ€˜์„ฑ๋Šฅ ํ™•๋ณดโ€™์™€ โ€˜์œ ์ง€๋ณด์ˆ˜ ์ƒ์‚ฐ์„ฑโ€™ ์‚ฌ์ด์—์„œ ์ตœ์ ์˜ ๊ท ํ˜•์ ์„ ์ฐพ์•„๋‚ด๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

Summary

I/O ๋ชจ๋ธ์€ ํ˜„๋Œ€ ๊ณ ์„ฑ๋Šฅ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ง€ํƒฑํ•˜๋Š” ๊ฐ€์žฅ ๊ทผ๋ณธ์ ์ธ ๊ธฐ๋‘ฅ์ž…๋‹ˆ๋‹ค. Blocking์˜ ์ง๊ด€์„ฑ์—์„œ ์‹œ์ž‘ํ•ด Non-Blocking์˜ ์ž์œ ๋ฅผ ๊ฑฐ์ณ, ๋ฆฌ๋ˆ…์Šค epoll๊ณผ Java NIO๋ผ๋Š” ๊ฑฐ๋Œ€ํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™”์˜ ์ •์ ์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ์—”์ง€๋‹ˆ์–ด๋Š” ๋Š์ž„์—†์ด CPU ์œ ํœด ์‹œ๊ฐ„์„ ์ค„์ด๊ณ  ์ž์› ํ™œ์šฉ๋„๋ฅผ ๋†’์ด๋Š” ํˆฌ์Ÿ์„ ์ด์–ด์™”์Šต๋‹ˆ๋‹ค. ์„ฑ๋Šฅ์˜ ์ž„๊ณ„์ ์€ ๊ฒฐ๊ตญ ์ปค๋„๊ณผ ์œ ์ € ์ŠคํŽ˜์ด์Šค ์‚ฌ์ด์˜ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ๋ฌธ๋งฅ ์ „ํ™˜ ๋น„์šฉ์„ ์–ผ๋งˆ๋‚˜ ์ •๊ตํ•˜๊ฒŒ ํ†ต์ œํ•˜๋А๋ƒ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

References

This post is licensed under CC BY 4.0 by the author.