เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

เชชเชฐเชฟเชšเชฏ

I/O เชฐเชฟเชเช•เซเชŸเชฐ (เชธเชฟเช‚เช—เชฒ เชฅเซเชฐเซ‡เชกเซ‡เชก เช‡เชตเซ‡เชจเซเชŸ เชฒเซ‚เชช) เช เชนเชพเช‡-เชฒเซ‹เชก เชธเซ‹เชซเซเชŸเชตเซ‡เชฐ เชฒเช–เชตเชพ เชฎเชพเชŸเซ‡เชจเซ€ เชชเซ‡เชŸเชฐเซเชจ เช›เซ‡, เชœเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช˜เชฃเชพ เชฒเซ‹เช•เชชเซเชฐเชฟเชฏ เช‰เช•เซ‡เชฒเซ‹เชฎเชพเช‚ เชฅเชพเชฏ เช›เซ‡:

เช† เชฒเซ‡เช–เชฎเชพเช‚, เช…เชฎเซ‡ I/O เชฐเชฟเชเช•เซเชŸเชฐเชจเชพ เช‡เชจเซเชธ เช…เชจเซ‡ เช†เช‰เชŸเซเชธ เชœเซ‹เชˆเชถเซเช‚ เช…เชจเซ‡ เชคเซ‡ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เช•เชพเชฐเซเชฏ เช•เชฐเซ‡ เช›เซ‡, เช•เซ‹เชกเชจเซ€ 200 เชฅเซ€ เช“เช›เซ€ เชฒเชพเช‡เชจเชฎเชพเช‚ เช…เชฎเชฒเซ€เช•เชฐเชฃ เชฒเช–เซ€เชถเซเช‚ เช…เชจเซ‡ 40 เชฎเชฟเชฒเชฟเชฏเชจ เชตเชฟเชจเช‚เชคเซ€เช“/เชฎเชฟเชจเชฟเชŸเชฅเซ€ เชตเชงเซ เชเช• เชธเชฐเชณ HTTP เชธเชฐเซเชตเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเซ€เชถเซเช‚.

เชซเซ‹เชฐเชตเชฐเซเชก

  • เชฒเซ‡เช– I/O เชฐเชฟเชเช•เซเชŸเชฐเชจเซ€ เช•เชพเชฎเช—เซ€เชฐเซ€เชจเซ‡ เชธเชฎเชœเชตเชพเชฎเชพเช‚ เชฎเชฆเชฆ เช•เชฐเชตเชพ เช…เชจเซ‡ เชคเซ‡เชฅเซ€ เชคเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชคเซ€ เชตเช–เชคเซ‡ เชœเซ‹เช–เชฎเซ‹เชจเซ‡ เชธเชฎเชœเชตเชพ เชฎเชพเชŸเซ‡ เชฒเช–เชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเซ‹ เชนเชคเซ‹.
  • เชฒเซ‡เช–เชจเซ‡ เชธเชฎเชœเชตเชพ เชฎเชพเชŸเซ‡ เชฎเซ‚เชณเชญเซ‚เชค เชฌเชพเชฌเชคเซ‹เชจเซเช‚ เชœเซเชžเชพเชจ เชœเชฐเซ‚เชฐเซ€ เช›เซ‡. เชธเซ€ เชญเชพเชทเชพ เช…เชจเซ‡ เชจเซ‡เชŸเชตเชฐเซเช• เชเชชเซเชฒเชฟเช•เซ‡เชถเชจ เชกเซ‡เชตเชฒเชชเชฎเซ‡เชจเซเชŸเชฎเชพเช‚ เชฅเซ‹เชกเซ‹ เช…เชจเซเชญเชต.
  • (เชธเชพเชตเชงเชพเชจ: เชฒเชพเช‚เชฌเซ€ PDF) C11 เชงเซ‹เชฐเชฃ เชธเซเชงเซ€ Linux เชฎเชพเชŸเซ‡ เช…เชจเซ‡ เชคเซ‡เชจเชพ เชชเชฐ เช‰เชชเชฒเชฌเซเชง เช›เซ‡ GitHub.

เชคเชฎเชพเชฐเซ‡ เชคเซ‡เชจเซ€ เช•เซ‡เชฎ เชœเชฐเซ‚เชฐ เช›เซ‡?

เชˆเชจเซเชŸเชฐเชจเซ‡เชŸเชจเซ€ เชตเชงเชคเซ€ เชœเชคเซ€ เชฒเซ‹เช•เชชเซเชฐเชฟเชฏเชคเชพ เชธเชพเชฅเซ‡, เชตเซ‡เชฌ เชธเชฐเซเชตเชฐเซเชธเชจเซ‡ เชเช•เชธเชพเชฅเซ‡ เชฎเซ‹เชŸเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ เช•เชจเซ‡เช•เซเชถเชจเซเชธ เชนเซ‡เชจเซเชกเชฒ เช•เชฐเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เชชเชกเซ€, เช…เชจเซ‡ เชคเซ‡เชฅเซ€ เชฌเซ‡ เช…เชญเชฟเช—เชฎเซ‹ เช…เชœเชฎเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเชพ: เชฎเซ‹เชŸเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ OS เชฅเซเชฐเซ‡เชกเซ‹ เชชเชฐ I/O เชจเซ‡ เช…เชตเชฐเซ‹เชงเชฟเชค เช•เชฐเชตเซเช‚ เช…เชจเซ‡ I/O เชจเซ‡ เช…เชตเชฐเซ‹เชงเชฟเชค เชจ เช•เชฐเชตเซเช‚ เช‡เชตเซ‡เชจเซเชŸ เชธเซ‚เชšเชจเชพ เชธเชฟเชธเซเชŸเชฎ, เชœเซ‡เชจเซ‡ "เชธเชฟเชธเซเชŸเชฎ เชธเชฟเชฒเซ‡เช•เซเชŸเชฐ" เชชเชฃ เช•เชนเซ‡เชตเชพเชฏ เช›เซ‡ (เช‡เชชเซ‹เชฒ/kqueue/IOCP/ เชตเช—เซ‡เชฐเซ‡).

เชชเซเชฐเชฅเชฎ เช…เชญเชฟเช—เชฎเชฎเชพเช‚ เชฆเชฐเซ‡เช• เช‡เชจเช•เชฎเชฟเช‚เช— เช•เชจเซ‡เช•เซเชถเชจ เชฎเชพเชŸเซ‡ เชจเชตเซ‹ OS เชฅเซเชฐเซ‡เชก เชฌเชจเชพเชตเชตเชพเชจเซ‹ เชธเชฎเชพเชตเซ‡เชถ เชฅเชพเชฏ เช›เซ‡. เชคเซ‡เชจเซ‹ เช—เซ‡เชฐเชฒเชพเชญ เชจเชฌเชณเซ€ เชฎเชพเชชเชจเซ€เชฏเชคเชพ เช›เซ‡: เช“เชชเชฐเซ‡เชŸเชฟเช‚เช— เชธเชฟเชธเซเชŸเชฎเชจเซ‡ เช˜เชฃเชพ เช…เชฎเชฒเชฎเชพเช‚ เชฎเซ‚เช•เชตเชพ เชชเชกเชถเซ‡ เชธเช‚เชฆเชฐเซเชญ เชธเช‚เช•เซเชฐเชฎเชฃเซ‹ ะธ เชธเชฟเชธเซเชŸเชฎ เช•เซ‰เชฒเซเชธ. เชคเซ‡ เช–เชฐเซเชšเชพเชณ เช•เชพเชฎเช—เซ€เชฐเซ€ เช›เซ‡ เช…เชจเซ‡ เชชเซเชฐเชญเชพเชตเชถเชพเชณเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ เช•เชจเซ‡เช•เซเชถเชจเซเชธ เชธเชพเชฅเซ‡ เชฎเชซเชค RAM เชจเซ‹ เช…เชญเชพเชต เชคเชฐเชซ เชฆเซ‹เชฐเซ€ เชถเช•เซ‡ เช›เซ‡.

เชธเช‚เชถเซ‹เชงเชฟเชค เชธเช‚เชธเซเช•เชฐเชฃ เชนเชพเช‡เชฒเชพเช‡เชŸเซเชธ เชฅเซเชฐเซ‡เชกเซ‹เชจเซ€ เชจเชฟเชถเซเชšเชฟเชค เชธเช‚เช–เซเชฏเชพ (เชฅเซเชฐเซ‡เชก เชชเซ‚เชฒ), เชคเซเชฏเชพเช‚ เชธเชฟเชธเซเชŸเชฎเชจเซ‡ เชเช•เซเชเซ‡เช•เซเชฏเซเชถเชจ เช…เชŸเช•เชพเชตเชตเชพเชฅเซ€ เช…เชŸเช•เชพเชตเซ‡ เช›เซ‡, เชชเชฐเช‚เชคเซ เชคเซ‡ เชœ เชธเชฎเชฏเซ‡ เชเช• เชจเชตเซ€ เชธเชฎเชธเซเชฏเชพ เชฐเชœเซ‚ เช•เชฐเซ‡ เช›เซ‡: เชœเซ‹ เชฅเซเชฐเซ‡เชก เชชเซ‚เชฒ เชนเชพเชฒเชฎเชพเช‚ เชฒเชพเช‚เชฌเชพ เชตเชพเช‚เชšเชจ เช•เชพเชฎเช—เซ€เชฐเซ€ เชฆเซเชตเชพเชฐเชพ เช…เชตเชฐเซ‹เชงเชฟเชค เช›เซ‡, เชคเซ‹ เชชเช›เซ€ เช…เชจเซเชฏ เชธเซ‹เช•เซ‡เชŸเซเชธ เช•เซ‡ เชœเซ‡ เชชเชนเซ‡เชฒเชพเชฅเซ€ เชกเซ‡เชŸเชพ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพเชฎเชพเช‚ เชธเช•เซเชทเชฎ เช›เซ‡ เชคเซ‡ เชธเช•เซเชทเชฎ เชฐเชนเซ‡เชถเซ‡ เชจเชนเซ€เช‚. เช†เชฎ เช•เชฐเซ‹

เชฌเซ€เชœเซ‹ เช…เชญเชฟเช—เชฎ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‡ เช›เซ‡ เช˜เชŸเชจเชพ เชธเซ‚เชšเชจเชพ เชธเชฟเชธเซเชŸเชฎ (เชธเชฟเชธเซเชŸเชฎ เชธเชฟเชฒเซ‡เช•เซเชŸเชฐ) OS เชฆเซเชตเชพเชฐเชพ เชชเซเชฐเชฆเชพเชจ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡. เช† เชฒเซ‡เช– I/O เช‘เชชเชฐเซ‡เชถเชจเซเชธ เชฎเชพเชŸเซ‡เชจเซ€ เชคเซˆเชฏเชพเชฐเซ€ เชตเชฟเชถเซ‡ เชšเซ‡เชคเชตเชฃเซ€เช“ (เช‡เชตเซ‡เชจเซเชŸเซเชธ, เชจเซ‹เชŸเชฟเชซเชฟเช•เซ‡เชถเชจ) เชชเชฐ เช†เชงเชพเชฐเชฟเชค, เชธเชฟเชธเซเชŸเชฎ เชธเชฟเชฒเซ‡เช•เซเชŸเชฐเชจเชพ เชธเซŒเชฅเซ€ เชธเชพเชฎเชพเชจเซเชฏ เชชเซเชฐเช•เชพเชฐเชจเซ€ เชšเชฐเซเชšเชพ เช•เชฐเซ‡ เช›เซ‡. เชคเซ‡เชฎเชจเซ€ เชชเซ‚เชฐเซเชฃเชคเชพ เชตเชฟเชถเซ‡ เชธเซ‚เชšเชจเชพเช“. เชคเซ‡เชจเชพ เช‰เชชเชฏเซ‹เช—เชจเซเช‚ เชเช• เชธเชฐเชณ เช‰เชฆเชพเชนเชฐเชฃ เชจเซ€เชšเซ‡เชจเชพ เชฌเซเชฒเซ‹เช• เชกเชพเชฏเชพเช—เซเชฐเชพเชฎ เชฆเซเชตเชพเชฐเชพ เชฐเชœเซ‚ เช•เชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡:

เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

เช† เช…เชญเชฟเช—เชฎเซ‹ เชตเชšเซเชšเซ‡เชจเซ‹ เชคเชซเชพเชตเชค เชจเซ€เชšเซ‡ เชฎเซเชœเชฌ เช›เซ‡:

  • I/O เช•เชพเชฎเช—เซ€เชฐเซ€เชจเซ‡ เช…เชตเชฐเซ‹เชงเชฟเชค เช•เชฐเซ€ เชฐเชนเซเชฏเชพ เช›เซ€เช เชธเชธเซเชชเซ‡เชจเซเชก เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชชเซเชฐเชตเชพเชน เชคเซเชฏเชพเช‚ เชธเซเชงเซ€เชœเซเชฏเชพเช‚ เชธเซเชงเซ€ OS เชฏเซ‹เช—เซเชฏ เชฐเซ€เชคเซ‡ เชจ เชฅเชพเชฏ เชคเซเชฏเชพเช‚ เชธเซเชงเซ€ เชกเชฟเชซเซเชฐเซ‡เช—เชฎเซ‡เชจเซเชŸเซเชธ เช‡เชจเช•เชฎเชฟเช‚เช— IP เชชเซ‡เช•เซ‡เชŸเซ‹ เชฌเชพเชˆเชŸ เชธเซเชŸเซเชฐเซ€เชฎ เชฎเชพเชŸเซ‡ (เชŸเซ€เชธเซ€เชชเซ€, เชกเซ‡เชŸเชพ เชชเซเชฐเชพเชชเซเชค เช•เชฐเซ€ เชฐเชนเซเชฏเซ‹ เช›เซ‡) เช…เชฅเชตเชพ เช†เช‚เชคเชฐเชฟเช• เชฒเซ‡เช–เชจ เชฌเชซเชฐเซเชธเชฎเชพเช‚ เช…เชจเซเช—เชพเชฎเซ€ เชฆเซเชตเชพเชฐเชพ เชฎเซ‹เช•เชฒเชตเชพ เชฎเชพเชŸเซ‡ เชชเซ‚เชฐเชคเซ€ เชœเช—เซเชฏเชพ เช‰เชชเชฒเชฌเซเชง เชฐเชนเซ‡เชถเซ‡ เชจเชนเซ€เช‚ เชเชจเช†เชˆเชธเซ€ (เชกเซ‡เชŸเชพ เชฎเซ‹เช•เชฒเซ€ เชฐเชนเซเชฏเซเช‚ เช›เซ‡).
  • เชธเชฟเชธเซเชŸเชฎ เชชเชธเช‚เชฆเช—เซ€เช•เชพเชฐ เชธเชฎเชฏ เชœเชคเชพเช‚ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชจเซ‡ เชธเซ‚เชšเชฟเชค เช•เชฐเซ‡ เช›เซ‡ เช•เซ‡ OS เชชเชนเซ‡เชฒเซ‡เชฅเซ€ เชกเชฟเชซเซเชฐเซ‡เช—เชฎเซ‡เชจเซเชŸเซ‡เชก IP เชชเซ‡เช•เซ‡เชŸเซเชธ (TCP, เชกเซ‡เชŸเชพ เชฐเชฟเชธเซ‡เชชเซเชถเชจ) เช…เชฅเชตเชพ เช†เช‚เชคเชฐเชฟเช• เชฒเช–เชพเชฃ เชฌเชซเชฐเซเชธเชฎเชพเช‚ เชชเซ‚เชฐเชคเซ€ เชœเช—เซเชฏเชพ เชชเชนเซ‡เชฒเซ‡เชฅเซ€ เช‰เชชเชฒเชฌเซเชง (เชกเซ‡เชŸเชพ เชฎเซ‹เช•เชฒเชตเชพ).

เชธเชพเชฐเชพเช‚เชถเชฎเชพเช‚ เช•เชนเซ€เช เชคเซ‹, เชฆเชฐเซ‡เช• I/O เชฎเชพเชŸเซ‡ OS เชฅเซเชฐเซ‡เชกเชจเซ‡ เช†เชฐเช•เซเชทเชฟเชค เชฐเชพเช–เชตเซ‹ เช เช•เชฎเซเชชเซเชฏเซเชŸเชฟเช‚เช— เชชเชพเชตเชฐเชจเซ‹ เชฌเช—เชพเชก เช›เซ‡, เช•เชพเชฐเชฃ เช•เซ‡ เชตเชพเชธเซเชคเชตเชฎเชพเช‚, เชฅเซเชฐเซ‡เชกเซ‹ เช‰เชชเชฏเซ‹เช—เซ€ เช•เชพเชฐเซเชฏ เช•เชฐเซ€ เชฐเชนเซเชฏเชพเช‚ เชจเชฅเซ€ (เชคเซ‡เชฅเซ€ เช† เชถเชฌเซเชฆ "เชธเซ‹เชซเซเชŸเชตเซ‡เชฐ เชตเชฟเช•เซเชทเซ‡เชช"). เชธเชฟเชธเซเชŸเชฎ เชธเชฟเชฒเซ‡เช•เซเชŸเชฐ เช† เชธเชฎเชธเซเชฏเชพเชจเซ‡ เช‰เช•เซ‡เชฒเซ‡ เช›เซ‡, เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชจเซ‡ CPU เชธเช‚เชธเชพเชงเชจเซ‹เชจเซ‹ เชตเชงเซ เช†เชฐเซเชฅเชฟเช• เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพเชจเซ€ เชฎเช‚เชœเซ‚เชฐเซ€ เช†เชชเซ‡ เช›เซ‡.

I/O เชฐเชฟเชเช•เซเชŸเชฐ เชฎเซ‹เชกเชฒ

I/O เชฐเชฟเชเช•เซเชŸเชฐ เชธเชฟเชธเซเชŸเชฎ เชชเชธเช‚เชฆเช—เซ€เช•เชพเชฐ เช…เชจเซ‡ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เช•เซ‹เชก เชตเชšเซเชšเซ‡เชจเชพ เชธเซเชคเชฐ เชคเชฐเซ€เช•เซ‡ เช•เชพเชฐเซเชฏ เช•เชฐเซ‡ เช›เซ‡. เชคเซ‡เชจเชพ เช“เชชเชฐเซ‡เชถเชจเชจเชพ เชธเชฟเชฆเซเชงเชพเช‚เชคเชจเซ‡ เชจเซ€เชšเซ‡เชจเชพ เชฌเซเชฒเซ‹เช• เชกเชพเชฏเชพเช—เซเชฐเชพเชฎ เชฆเซเชตเชพเชฐเชพ เชตเชฐเซเชฃเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡:

เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

  • เชนเซเช‚ เชคเชฎเชจเซ‡ เชฏเชพเชฆ เช…เชชเชพเชตเซ€ เชฆเช‰เช‚ เช•เซ‡ เช‡เชตเซ‡เชจเซเชŸ เช เชธเซ‚เชšเชจเชพ เช›เซ‡ เช•เซ‡ เชšเซ‹เช•เซเช•เชธ เชธเซ‹เช•เซ‡เชŸ เชฌเชฟเชจ-เชฌเซเชฒเซ‹เช•เชฟเช‚เช— I/O เช‘เชชเชฐเซ‡เชถเชจ เช•เชฐเชตเชพ เชธเช•เซเชทเชฎ เช›เซ‡.
  • เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐ เช เชเช• เช•เชพเชฐเซเชฏ เช›เซ‡ เชœเซ‡เชจเซ‡ I/O เชฐเชฟเชเช•เซเชŸเชฐ เชฆเซเชตเชพเชฐเชพ เช•เชนเซ‡เชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ เชœเซเชฏเชพเชฐเซ‡ เช‡เชตเซ‡เชจเซเชŸ เชชเซเชฐเชพเชชเซเชค เชฅเชพเชฏ เช›เซ‡, เชœเซ‡ เชชเช›เซ€ เชฌเชฟเชจ-เชฌเซเชฒเซ‹เช•เชฟเช‚เช— I/O เช‘เชชเชฐเซ‡เชถเชจ เช•เชฐเซ‡ เช›เซ‡.

เช เชจเซ‹เช‚เชงเชตเซเช‚ เช…เช—เชคเซเชฏเชจเซเช‚ เช›เซ‡ เช•เซ‡ I/O เชฐเชฟเชเช•เซเชŸเชฐ เชตเซเชฏเชพเช–เซเชฏเชพ เชชเซเชฐเชฎเชพเชฃเซ‡ เชธเชฟเช‚เช—เชฒ-เชฅเซเชฐเซ‡เชกเซ‡เชก เช›เซ‡, เชชเชฐเช‚เชคเซ 1 เชฅเซเชฐเซ‡เชก: 1 เชฐเชฟเชเช•เซเชŸเชฐเชจเชพ เช—เซเชฃเซ‹เชคเซเชคเชฐเชฎเชพเช‚ เชฎเชฒเซเชŸเชฟ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชตเชพเชคเชพเชตเชฐเชฃเชฎเชพเช‚ เช–เซเชฏเชพเชฒเชจเซ‡ เช‰เชชเชฏเซ‹เช—เชฎเชพเช‚ เชฒเซ‡เชตเชพเชฅเซ€ เช•เช‚เชˆ เช…เชŸเช•เชพเชตเชคเซเช‚ เชจเชฅเซ€, เชคเซเชฏเชพเช‚เชฅเซ€ เชคเชฎเชพเชฎ CPU เช•เซ‹เชฐเซ‹ เชฐเชฟเชธเชพเชฏเช•เซเชฒเชฟเช‚เช— เชฅเชพเชฏ เช›เซ‡.

ะ ะตะฐะปะธะทะฐั†ะธั

เช…เชฎเซ‡ เชธเชพเชฐเซเชตเชœเชจเชฟเช• เช‡เชจเซเชŸเชฐเชซเซ‡เชธเชจเซ‡ เชซเชพเช‡เชฒเชฎเชพเช‚ เชฎเซ‚เช•เซ€เชถเซเช‚ reactor.h, เช…เชจเซ‡ เช…เชฎเชฒเซ€เช•เชฐเชฃ - เชฎเชพเช‚ reactor.c. reactor.h เชจเซ€เชšเซ‡เชจเซ€ เช˜เซ‹เชทเชฃเชพเช“เชจเซ‹ เชธเชฎเชพเชตเซ‡เชถ เชฅเชถเซ‡:

reactor.h เชฎเชพเช‚ เช˜เซ‹เชทเชฃเชพเช“ เชฌเชคเชพเชตเซ‹

typedef struct reactor Reactor;

/*
 * ะฃะบะฐะทะฐั‚ะตะปัŒ ะฝะฐ ั„ัƒะฝะบั†ะธัŽ, ะบะพั‚ะพั€ะฐั ะฑัƒะดะตั‚ ะฒั‹ะทั‹ะฒะฐั‚ัŒัั I/O ั€ะตะฐะบั‚ะพั€ะพะผ ะฟั€ะธ ะฟะพัั‚ัƒะฟะปะตะฝะธะธ
 * ัะพะฑั‹ั‚ะธั ะพั‚ ัะธัั‚ะตะผะฝะพะณะพ ัะตะปะตะบั‚ะพั€ะฐ.
 */
typedef void (*Callback)(void *arg, int fd, uint32_t events);

/*
 * ะ’ะพะทะฒั€ะฐั‰ะฐะตั‚ `NULL` ะฒ ัะปัƒั‡ะฐะต ะพัˆะธะฑะบะธ, ะฝะต-`NULL` ัƒะบะฐะทะฐั‚ะตะปัŒ ะฝะฐ `Reactor` ะฒ
 * ะฟั€ะพั‚ะธะฒะฝะพะผ ัะปัƒั‡ะฐะต.
 */
Reactor *reactor_new(void);

/*
 * ะžัะฒะพะฑะพะถะดะฐะตั‚ ัะธัั‚ะตะผะฝั‹ะน ัะตะปะตะบั‚ะพั€, ะฒัะต ะทะฐั€ะตะณะธัั‚ั€ะธั€ะพะฒะฐะฝะฝั‹ะต ัะพะบะตั‚ั‹ ะฒ ะดะฐะฝะฝั‹ะน ะผะพะผะตะฝั‚
 * ะฒั€ะตะผะตะฝะธ ะธ ัะฐะผ I/O ั€ะตะฐะบั‚ะพั€.
 *
 * ะกะปะตะดัƒัŽั‰ะธะต ั„ัƒะฝะบั†ะธะธ ะฒะพะทะฒั€ะฐั‰ะฐัŽั‚ -1 ะฒ ัะปัƒั‡ะฐะต ะพัˆะธะฑะบะธ, 0 ะฒ ัะปัƒั‡ะฐะต ัƒัะฟะตั…ะฐ.
 */
int reactor_destroy(Reactor *reactor);

int reactor_register(const Reactor *reactor, int fd, uint32_t interest,
                     Callback callback, void *callback_arg);
int reactor_deregister(const Reactor *reactor, int fd);
int reactor_reregister(const Reactor *reactor, int fd, uint32_t interest,
                       Callback callback, void *callback_arg);

/*
 * ะ—ะฐะฟัƒัะบะฐะตั‚ ั†ะธะบะป ัะพะฑั‹ั‚ะธะน ั ั‚ะฐะนะผ-ะฐัƒั‚ะพะผ `timeout`.
 *
 * ะญั‚ะฐ ั„ัƒะฝะบั†ะธั ะฟะตั€ะตะดะฐัั‚ ัƒะฟั€ะฐะฒะปะตะฝะธะต ะฒั‹ะทั‹ะฒะฐัŽั‰ะตะผัƒ ะบะพะดัƒ ะตัะปะธ ะพั‚ะฒะตะดั‘ะฝะฝะพะต ะฒั€ะตะผั ะฒั‹ัˆะปะพ
 * ะธะปะธ/ะธ ะฟั€ะธ ะพั‚ััƒั‚ัั‚ะฒะธะธ ะทะฐั€ะตะณะธัั‚ั€ะธั€ะพะฒะฐะฝะฝั‹ั… ัะพะบะตั‚ะพะฒ.
 */
int reactor_run(const Reactor *reactor, time_t timeout);

I/O เชฐเชฟเชเช•เซเชŸเชฐ เชฎเชพเชณเช–เซเช‚ เชธเชฎเชพเชตเซ‡ เช›เซ‡ เชซเชพเช‡เชฒ เชตเชฐเซเชฃเชจเช•เชฐเซเชคเชพ เชชเชธเช‚เชฆเช—เซ€เช•เชพเชฐ เช‡เชชเซ‹เชฒ ะธ เชนเซ‡เชถ เช•เซ‹เชทเซเชŸเช•เซ‹ GHashTable, เชœเซ‡ เชฆเชฐเซ‡เช• เชธเซ‹เช•เซ‡เชŸเชจเซ‡ เชฎเซ‡เชช เช•เชฐเซ‡ เช›เซ‡ CallbackData (เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐเชจเซเช‚ เชฎเชพเชณเช–เซเช‚ เช…เชจเซ‡ เชคเซ‡เชจเชพ เชฎเชพเชŸเซ‡ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชฆเชฒเซ€เชฒ).

เชฐเชฟเชเช•เซเชŸเชฐ เช…เชจเซ‡ เช•เซ‰เชฒเชฌเซ‡เช•เชกเซ‡เชŸเชพ เชฌเชคเชพเชตเซ‹

struct reactor {
    int epoll_fd;
    GHashTable *table; // (int, CallbackData)
};

typedef struct {
    Callback callback;
    void *arg;
} CallbackData;

เชฎเชนเซ‡เชฐเชฌเชพเชจเซ€ เช•เชฐเซ€เชจเซ‡ เชจเซ‹เช‚เชง เช•เชฐเซ‹ เช•เซ‡ เช…เชฎเซ‡ เชนเซ‡เชจเซเชกเชฒ เช•เชฐเชตเชพเชจเซ€ เช•เซเชทเชฎเชคเชพเชจเซ‡ เชธเช•เซเชทเชฎ เช•เชฐเซ€ เช›เซ‡ เช…เชชเซ‚เชฐเซเชฃ เชชเซเชฐเช•เชพเชฐ เช‡เชจเซเชกเซ‡เช•เซเชธ เช…เชจเซเชธเชพเชฐ. IN reactor.h เช…เชฎเซ‡ เชฎเชพเชณเช–เซเช‚ เชœเชพเชนเซ‡เชฐ เช•เชฐเซ€เช เช›เซ€เช reactor, เช…เชจเซ‡ เชฎเชพเช‚ reactor.c เช…เชฎเซ‡ เชคเซ‡เชจเซ‡ เชตเซเชฏเชพเช–เซเชฏเชพเชฏเชฟเชค เช•เชฐเซ€เช เช›เซ€เช, เชคเซ‡เชฅเซ€ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพเชจเซ‡ เชคเซ‡เชจเชพ เช•เซเชทเซ‡เชคเซเชฐเซ‹เชจเซ‡ เชธเซเชชเชทเซเชŸเชชเชฃเซ‡ เชฌเชฆเชฒเชตเชพเชฅเซ€ เช…เชŸเช•เชพเชตเซ‡ เช›เซ‡. เช† เชเช• เชชเซ‡เชŸเชฐเซเชจ เช›เซ‡ เชกเซ‡เชŸเชพ เช›เซเชชเชพเชตเซ‡ เช›เซ‡, เชœเซ‡ เชธเช‚เช•เซเชทเชฟเชชเซเชค เชฐเซ€เชคเซ‡ C เชธเชฟเชฎเซ‡เชจเซเชŸเชฟเช•เซเชธเชฎเชพเช‚ เชฌเช‚เชงเชฌเซ‡เชธเซ‡ เช›เซ‡.

เช•เชพเชฐเซเชฏเซ‹ reactor_register, reactor_deregister ะธ reactor_reregister เชธเชฟเชธเซเชŸเชฎ เชชเชธเช‚เชฆเช—เซ€เช•เชพเชฐ เช…เชจเซ‡ เชนเซ‡เชถ เชŸเซ‡เชฌเชฒเชฎเชพเช‚ เชฐเซเชšเชฟเชจเชพ เชธเซ‹เช•เซ‡เชŸเซเชธ เช…เชจเซ‡ เช…เชจเซเชฐเซ‚เชช เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐเซเชธเชจเซ€ เชธเซ‚เชšเชฟเชจเซ‡ เช…เชชเชกเซ‡เชŸ เช•เชฐเซ‹.

เชจเซ‹เช‚เชงเชฃเซ€ เช•เชพเชฐเซเชฏเซ‹ เชฌเชคเชพเชตเซ‹

#define REACTOR_CTL(reactor, op, fd, interest)                                 
    if (epoll_ctl(reactor->epoll_fd, op, fd,                                   
                  &(struct epoll_event){.events = interest,                    
                                        .data = {.fd = fd}}) == -1) {          
        perror("epoll_ctl");                                                   
        return -1;                                                             
    }

int reactor_register(const Reactor *reactor, int fd, uint32_t interest,
                     Callback callback, void *callback_arg) {
    REACTOR_CTL(reactor, EPOLL_CTL_ADD, fd, interest)
    g_hash_table_insert(reactor->table, int_in_heap(fd),
                        callback_data_new(callback, callback_arg));
    return 0;
}

int reactor_deregister(const Reactor *reactor, int fd) {
    REACTOR_CTL(reactor, EPOLL_CTL_DEL, fd, 0)
    g_hash_table_remove(reactor->table, &fd);
    return 0;
}

int reactor_reregister(const Reactor *reactor, int fd, uint32_t interest,
                       Callback callback, void *callback_arg) {
    REACTOR_CTL(reactor, EPOLL_CTL_MOD, fd, interest)
    g_hash_table_insert(reactor->table, int_in_heap(fd),
                        callback_data_new(callback, callback_arg));
    return 0;
}

I/O เชฐเชฟเชเช•เซเชŸเชฐเซ‡ เชตเชฐเซเชฃเชจเช•เชฐเซเชคเชพ เชธเชพเชฅเซ‡ เช˜เชŸเชจเชพเชจเซ‡ เช…เชŸเช•เชพเชตเซเชฏเชพ เชชเช›เซ€ fd, เชคเซ‡ เชธเช‚เชฌเช‚เชงเชฟเชค เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐเชจเซ‡ เช•เซ‰เชฒ เช•เชฐเซ‡ เช›เซ‡, เชœเซ‡เชจเชพเชฅเซ€ เชคเซ‡ เชชเชธเชพเชฐ เชฅเชพเชฏ เช›เซ‡ fd, เชฌเซ€เชŸ เชฎเชพเชธเซเช• เชœเชจเชฐเซ‡เชŸ เช•เชฐเซ‡เชฒ เช‡เชตเซ‡เชจเซเชŸเซเชธ เช…เชจเซ‡ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชจเชฟเชฐเซเชฆเซ‡เชถเช• void.

เชฐเชฟเชเช•เซเชŸเชฐ_เชฐเชจ() เชซเช‚เช•เซเชถเชจ เชฌเชคเชพเชตเซ‹

int reactor_run(const Reactor *reactor, time_t timeout) {
    int result;
    struct epoll_event *events;
    if ((events = calloc(MAX_EVENTS, sizeof(*events))) == NULL)
        abort();

    time_t start = time(NULL);

    while (true) {
        time_t passed = time(NULL) - start;
        int nfds =
            epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, timeout - passed);

        switch (nfds) {
        // ะžัˆะธะฑะบะฐ
        case -1:
            perror("epoll_wait");
            result = -1;
            goto cleanup;
        // ะ’ั€ะตะผั ะฒั‹ัˆะปะพ
        case 0:
            result = 0;
            goto cleanup;
        // ะฃัะฟะตัˆะฝะฐั ะพะฟะตั€ะฐั†ะธั
        default:
            // ะ’ั‹ะทะฒะฐั‚ัŒ ะพะฑั€ะฐะฑะพั‚ั‡ะธะบะพะฒ ัะพะฑั‹ั‚ะธะน
            for (int i = 0; i < nfds; i++) {
                int fd = events[i].data.fd;

                CallbackData *callback =
                    g_hash_table_lookup(reactor->table, &fd);
                callback->callback(callback->arg, fd, events[i].events);
            }
        }
    }

cleanup:
    free(events);
    return result;
}

เชธเชพเชฐเชพเช‚เชถ เชฎเชพเชŸเซ‡, เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เช•เซ‹เชกเชฎเชพเช‚ เชซเช‚เช•เซเชถเชจ เช•เซ‰เชฒเซเชธเชจเซ€ เชธเชพเช‚เช•เชณ เชจเซ€เชšเซ‡เชจเซเช‚ เชธเซเชตเชฐเซ‚เชช เชฒเซ‡เชถเซ‡:

เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

เชธเชฟเช‚เช—เชฒ เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐ

เช‰เชšเซเชš เชฒเซ‹เชก เชนเซ‡เช เชณ I/O เชฐเชฟเชเช•เซเชŸเชฐเชจเซเช‚ เชชเชฐเซ€เช•เซเชทเชฃ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เชเช• เชธเชฐเชณ HTTP เชตเซ‡เชฌ เชธเชฐเซเชตเชฐ เชฒเช–เซ€เชถเซเช‚ เชœเซ‡ เช›เชฌเซ€ เชธเชพเชฅเซ‡เชจเซ€ เช•เซ‹เชˆเชชเชฃ เชตเชฟเชจเช‚เชคเซ€เชจเซ‹ เชœเชตเชพเชฌ เช†เชชเซ‡ เช›เซ‡.

HTTP เชชเซเชฐเซ‹เชŸเซ‹เช•เซ‹เชฒเชจเซ‹ เชเชกเชชเซ€ เชธเช‚เชฆเชฐเซเชญ

HTTP - เช† เชชเซเชฐเซ‹เชŸเซ‹เช•เซ‹เชฒ เช›เซ‡ เชเชชเซเชฒเชฟเช•เซ‡เชถเชจ เชธเซเชคเชฐ, เชฎเซเช–เซเชฏเชคเซเชตเซ‡ เชธเชฐเซเชตเชฐ-เชฌเซเชฐเชพเช‰เชเชฐ เช•เซเชฐเชฟเชฏเชพเชชเซเชฐเชคเชฟเช•เซเชฐเชฟเชฏเชพ เชฎเชพเชŸเซ‡ เชตเชชเชฐเชพเชฏ เช›เซ‡.

HTTP เชจเซ‹ เช‰เชชเชฏเซ‹เช— เชธเชฐเชณเชคเชพเชฅเซ€ เช•เชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡ เชชเชฐเชฟเชตเชนเชจ เชชเซเชฐเซ‹เชŸเซ‹เช•เซ‹เชฒ เชŸเซ€เชธเซ€เชชเซ€, เช‰เชฒเซเชฒเซ‡เช–เชฟเชค เชซเซ‹เชฐเซเชฎเซ‡เชŸเชฎเชพเช‚ เชธเช‚เชฆเซ‡เชถเชพ เชฎเซ‹เช•เชฒเชตเชพ เช…เชจเซ‡ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพ เชธเซเชชเชทเซเชŸเซ€เช•เชฐเชฃ.

เชตเชฟเชจเช‚เชคเซ€ เชซเซ‹เชฐเซเชฎเซ‡เชŸ

<ะšะžะœะะะ”ะ> <URI> <ะ’ะ•ะ ะกะ˜ะฏ HTTP>CRLF
<ะ—ะะ“ะžะ›ะžะ’ะžะš 1>CRLF
<ะ—ะะ“ะžะ›ะžะ’ะžะš 2>CRLF
<ะ—ะะ“ะžะ›ะžะ’ะžะš N>CRLF CRLF
<ะ”ะะะะซะ•>

  • CRLF เชฌเซ‡ เช…เช•เซเชทเชฐเซ‹เชจเซ‹ เช•เซเชฐเชฎ เช›เซ‡: r ะธ n, เชตเชฟเชจเช‚เชคเซ€เชจเซ€ เชชเซเชฐเชฅเชฎ เชฒเชพเช‡เชจ, เชนเซ‡เชกเชฐเซ‹ เช…เชจเซ‡ เชกเซ‡เชŸเชพเชจเซ‡ เช…เชฒเช— เช•เชฐเซ€เชจเซ‡.
  • <ะšะžะœะะะ”ะ> - เชฎเชพเชจเซ‚ เชเช• CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE. เชฌเซเชฐเชพเช‰เชเชฐ เช…เชฎเชพเชฐเชพ เชธเชฐเซเชตเชฐเชจเซ‡ เช†เชฆเซ‡เชถ เชฎเซ‹เช•เชฒเชถเซ‡ GET, เชœเซ‡เชจเซ‹ เช…เชฐเซเชฅ เชฅเชพเชฏ เช›เซ‡ "เชฎเชจเซ‡ เชซเชพเช‡เชฒเชจเซ€ เชธเชพเชฎเช—เซเชฐเซ€ เชฎเซ‹เช•เชฒเซ‹."
  • <URI> - เชธเชฎเชพเชจ เชธเช‚เชธเชพเชงเชจ เช“เชณเช–เช•เชฐเซเชคเชพ. เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชœเซ‹ URI = /index.html, เชชเช›เซ€ เช•เซเชฒเชพเชฏเช‚เชŸ เชธเชพเช‡เชŸเชจเชพ เชฎเซเช–เซเชฏ เชชเซƒเชทเซเช เชจเซ€ เชตเชฟเชจเช‚เชคเซ€ เช•เชฐเซ‡ เช›เซ‡.
  • <ะ’ะ•ะ ะกะ˜ะฏ HTTP> โ€” เชซเซ‹เชฐเซเชฎเซ‡เชŸเชฎเชพเช‚ HTTP เชชเซเชฐเซ‹เชŸเซ‹เช•เซ‹เชฒเชจเซเช‚ เชธเช‚เชธเซเช•เชฐเชฃ HTTP/X.Y. เช†เชœเซ‡ เชธเซŒเชฅเซ€ เชตเชงเซ เช‰เชชเชฏเซ‹เช—เชฎเชพเช‚ เชฒเซ‡เชตเชพเชคเซเช‚ เชธเช‚เชธเซเช•เชฐเชฃ เช›เซ‡ HTTP/1.1.
  • <ะ—ะะ“ะžะ›ะžะ’ะžะš N> เชซเซ‹เชฐเซเชฎเซ‡เชŸเชฎเชพเช‚ เช•เซ€-เชตเซ‡เชฒเซเชฏเซ เชœเซ‹เชกเซ€ เช›เซ‡ <ะšะ›ะฎะง>: <ะ—ะะะงะ•ะะ˜ะ•>, เชตเชงเซ เชตเชฟเชถเซเชฒเซ‡เชทเชฃ เชฎเชพเชŸเซ‡ เชธเชฐเซเชตเชฐ เชชเชฐ เชฎเซ‹เช•เชฒเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡.
  • <ะ”ะะะะซะ•> - เช“เชชเชฐเซ‡เชถเชจ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชธเชฐเซเชตเชฐ เชฆเซเชตเชพเชฐเชพ เชœเชฐเซ‚เชฐเซ€ เชกเซ‡เชŸเชพ. เช˜เชฃเซ€เชตเชพเชฐ เชคเซ‡ เชธเชฐเชณ เช›เซ‡ JSON เช…เชฅเชตเชพ เช•เซ‹เชˆเชชเชฃ เช…เชจเซเชฏ เชซเซ‹เชฐเซเชฎเซ‡เชŸ.

เชชเซเชฐเชคเชฟเชญเชพเชต เชซเซ‹เชฐเซเชฎเซ‡เชŸ

<ะ’ะ•ะ ะกะ˜ะฏ HTTP> <ะšะžะ” ะกะขะะขะฃะกะ> <ะžะŸะ˜ะกะะะ˜ะ• ะกะขะะขะฃะกะ>CRLF
<ะ—ะะ“ะžะ›ะžะ’ะžะš 1>CRLF
<ะ—ะะ“ะžะ›ะžะ’ะžะš 2>CRLF
<ะ—ะะ“ะžะ›ะžะ’ะžะš N>CRLF CRLF
<ะ”ะะะะซะ•>

  • <ะšะžะ” ะกะขะะขะฃะกะ> เช“เชชเชฐเซ‡เชถเชจเชจเชพ เชชเชฐเชฟเชฃเชพเชฎเชจเซ‡ เชฐเชœเซ‚ เช•เชฐเชคเซ€ เชธเช‚เช–เซเชฏเชพ เช›เซ‡. เช…เชฎเชพเชฐเซเช‚ เชธเชฐเซเชตเชฐ เชนเช‚เชฎเซ‡เชถเชพ เชธเซเชŸเซ‡เชŸเชธ 200 (เชธเชซเชณ เช•เชพเชฎเช—เซ€เชฐเซ€) เชชเชฐเชค เช•เชฐเชถเซ‡.
  • <ะžะŸะ˜ะกะะะ˜ะ• ะกะขะะขะฃะกะ> - เชธเซเชŸเซ‡เชŸเชธ เช•เซ‹เชกเชจเซ€ เชธเซเชŸเซเชฐเชฟเช‚เช— เชฐเชœเซ‚เช†เชค. เชธเซเชŸเซ‡เชŸเชธ เช•เซ‹เชก 200 เชฎเชพเชŸเซ‡ เช† เช›เซ‡ OK.
  • <ะ—ะะ“ะžะ›ะžะ’ะžะš N> โ€” เชตเชฟเชจเช‚เชคเซ€เชฎเชพเช‚เชจเชพ เชธเชฎเชพเชจ เชซเซ‹เชฐเซเชฎเซ‡เชŸเชจเซเช‚ เชนเซ‡เชกเชฐ. เช…เชฎเซ‡ เชŸเชพเช‡เชŸเชฒ เชชเชฐเชค เช•เชฐเซ€เชถเซเช‚ Content-Length (เชซเชพเช‡เชฒเชจเซเช‚ เช•เชฆ) เช…เชจเซ‡ Content-Type: text/html (เชฐเซ€เชŸเชฐเซเชจ เชกเซ‡เชŸเชพ เชชเซเชฐเช•เชพเชฐ).
  • <ะ”ะะะะซะ•> - เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพ เชฆเซเชตเชพเชฐเชพ เชตเชฟเชจเช‚เชคเซ€ เช•เชฐเชพเชฏเซ‡เชฒ เชกเซ‡เชŸเชพ. เช…เชฎเชพเชฐเชพ เช•เชฟเชธเซเชธเชพเชฎเชพเช‚, เช† เชฎเชพเช‚เชจเซ€ เช›เชฌเซ€เชจเซ‹ เชฎเชพเชฐเซเช— เช›เซ‡ HTML.

เชซเชพเชˆเชฒ http_server.c (เชธเชฟเช‚เช—เชฒ เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐ) เชซเชพเช‡เชฒเชจเซ‹ เชธเชฎเชพเชตเซ‡เชถ เช•เชฐเซ‡ เช›เซ‡ common.h, เชœเซ‡เชฎเชพเช‚ เชจเซ€เชšเซ‡เชจเชพ เชซเช‚เช•เซเชถเชจ เชชเซเชฐเซ‹เชŸเซ‹เชŸเชพเช‡เชชเซเชธ เช›เซ‡:

เชธเชพเชฎเชพเชจเซเชฏเชฎเชพเช‚ เชซเช‚เช•เซเชถเชจ เชชเซเชฐเซ‹เชŸเซ‹เชŸเชพเช‡เชช เชฌเชคเชพเชตเซ‹

/*
 * ะžะฑั€ะฐะฑะพั‚ั‡ะธะบ ัะพะฑั‹ั‚ะธะน, ะบะพั‚ะพั€ั‹ะน ะฒั‹ะทะพะฒะตั‚ัั ะฟะพัะปะต ั‚ะพะณะพ, ะบะฐะบ ัะพะบะตั‚ ะฑัƒะดะตั‚
 * ะณะพั‚ะพะฒ ะฟั€ะธะฝัั‚ัŒ ะฝะพะฒะพะต ัะพะตะดะธะฝะตะฝะธะต.
 */
static void on_accept(void *arg, int fd, uint32_t events);

/*
 * ะžะฑั€ะฐะฑะพั‚ั‡ะธะบ ัะพะฑั‹ั‚ะธะน, ะบะพั‚ะพั€ั‹ะน ะฒั‹ะทะพะฒะตั‚ัั ะฟะพัะปะต ั‚ะพะณะพ, ะบะฐะบ ัะพะบะตั‚ ะฑัƒะดะตั‚
 * ะณะพั‚ะพะฒ ะพั‚ะฟั€ะฐะฒะธั‚ัŒ HTTP ะพั‚ะฒะตั‚.
 */
static void on_send(void *arg, int fd, uint32_t events);

/*
 * ะžะฑั€ะฐะฑะพั‚ั‡ะธะบ ัะพะฑั‹ั‚ะธะน, ะบะพั‚ะพั€ั‹ะน ะฒั‹ะทะพะฒะตั‚ัั ะฟะพัะปะต ั‚ะพะณะพ, ะบะฐะบ ัะพะบะตั‚ ะฑัƒะดะตั‚
 * ะณะพั‚ะพะฒ ะฟั€ะธะฝัั‚ัŒ ั‡ะฐัั‚ัŒ HTTP ะทะฐะฟั€ะพัะฐ.
 */
static void on_recv(void *arg, int fd, uint32_t events);

/*
 * ะŸะตั€ะตะฒะพะดะธั‚ ะฒั…ะพะดัั‰ะตะต ัะพะตะดะธะฝะตะฝะธะต ะฒ ะฝะตะฑะปะพะบะธั€ัƒัŽั‰ะธะน ั€ะตะถะธะผ.
 */
static void set_nonblocking(int fd);

/*
 * ะŸะตั‡ะฐั‚ะฐะตั‚ ะฟะตั€ะตะดะฐะฝะฝั‹ะต ะฐั€ะณัƒะผะตะฝั‚ั‹ ะฒ stderr ะธ ะฒั‹ั…ะพะดะธั‚ ะธะท ะฟั€ะพั†ะตััะฐ ั
 * ะบะพะดะพะผ `EXIT_FAILURE`.
 */
static noreturn void fail(const char *format, ...);

/*
 * ะ’ะพะทะฒั€ะฐั‰ะฐะตั‚ ั„ะฐะนะปะพะฒั‹ะน ะดะตัะบั€ะธะฟั‚ะพั€ ัะพะบะตั‚ะฐ, ัะฟะพัะพะฑะฝะพะณะพ ะฟั€ะธะฝะธะผะฐั‚ัŒ ะฝะพะฒั‹ะต
 * TCP ัะพะตะดะธะฝะตะฝะธั.
 */
static int new_server(bool reuse_port);

เช•เชพเชฐเซเชฏเชพเชคเซเชฎเช• เชฎเซ‡เช•เซเชฐเซ‹ เชชเชฃ เชตเชฐเซเชฃเชตเซ‡เชฒ เช›เซ‡ SAFE_CALL() เช…เชจเซ‡ เช•เชพเชฐเซเชฏ เชตเซเชฏเชพเช–เซเชฏเชพเชฏเชฟเชค เชฅเชฏเซ‡เชฒ เช›เซ‡ fail(). เชฎเซ‡เช•เซเชฐเซ‹ เช…เชญเชฟเชตเซเชฏเช•เซเชคเชฟเชจเชพ เชฎเซ‚เชฒเซเชฏเชจเซ€ เชญเซ‚เชฒ เชธเชพเชฅเซ‡ เชคเซเชฒเชจเชพ เช•เชฐเซ‡ เช›เซ‡, เช…เชจเซ‡ เชœเซ‹ เชธเซเชฅเชฟเชคเชฟ เชธเชพเชšเซ€ เชนเซ‹เชฏ, เชคเซ‹ เชซเช‚เช•เซเชถเชจเชจเซ‡ เช•เซ‰เชฒ เช•เชฐเซ‡ เช›เซ‡ fail():

#define SAFE_CALL(call, error)                                                 
    do {                                                                       
        if ((call) == error) {                                                   
            fail("%s", #call);                                                 
        }                                                                      
    } while (false)

เช•เชพเชฐเซเชฏ fail() เชชเชธเชพเชฐ เชฅเชฏเซ‡เชฒเซ€ เชฆเชฒเซ€เชฒเซ‹เชจเซ‡ เชŸเชฐเซเชฎเชฟเชจเชฒ เชชเชฐ เช›เชพเชชเซ‡ เช›เซ‡ (เชœเซ‡เชฎ เช•เซ‡ printf()) เช…เชจเซ‡ เช•เซ‹เชก เชธเชพเชฅเซ‡ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชจเซ‡ เชธเชฎเชพเชชเซเชค เช•เชฐเซ‡ เช›เซ‡ EXIT_FAILURE:

static noreturn void fail(const char *format, ...) {
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    fprintf(stderr, ": %sn", strerror(errno));
    exit(EXIT_FAILURE);
}

เช•เชพเชฐเซเชฏ new_server() เชธเชฟเชธเซเชŸเชฎ เช•เซ‹เชฒเซเชธ เชฆเซเชตเชพเชฐเชพ เชฌเชจเชพเชตเซ‡เชฒ "เชธเชฐเซเชตเชฐ" เชธเซ‹เช•เซ‡เชŸเชจเซเช‚ เชซเชพเช‡เชฒ เชตเชฐเซเชฃเชจเช•เชฐเซเชคเชพ เชชเชฐเชค เช•เชฐเซ‡ เช›เซ‡ socket(), bind() ะธ listen() เช…เชจเซ‡ เชจเซ‰เชจ-เชฌเซเชฒเซ‰เช•เชฟเช‚เช— เชฎเซ‹เชกเชฎเชพเช‚ เช‡เชจเช•เชฎเชฟเช‚เช— เช•เชจเซ‡เช•เซเชถเชจ เชธเซเชตเซ€เช•เชพเชฐเชตเชพ เชธเช•เซเชทเชฎ เช›เซ‡.

new_server() เชซเช‚เช•เซเชถเชจ เชฌเชคเชพเชตเซ‹

static int new_server(bool reuse_port) {
    int fd;
    SAFE_CALL((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP)),
              -1);

    if (reuse_port) {
        SAFE_CALL(
            setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)),
            -1);
    }

    struct sockaddr_in addr = {.sin_family = AF_INET,
                               .sin_port = htons(SERVER_PORT),
                               .sin_addr = {.s_addr = inet_addr(SERVER_IPV4)},
                               .sin_zero = {0}};

    SAFE_CALL(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), -1);
    SAFE_CALL(listen(fd, SERVER_BACKLOG), -1);
    return fd;
}

  • เชจเซ‹เช‚เชง เช•เชฐเซ‹ เช•เซ‡ เชธเซ‹เช•เซ‡เชŸ เชถเชฐเซ‚เช†เชคเชฎเชพเช‚ เชซเซเชฒเซ‡เช—เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชฌเชฟเชจ-เช…เชตเชฐเซ‹เชงเชฟเชค เชฎเซ‹เชกเชฎเชพเช‚ เชฌเชจเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ SOCK_NONBLOCKเชœเซ‡เชฅเซ€ เช•เชพเชฐเซเชฏเชฎเชพเช‚ on_accept() (เชตเชงเซ เชตเชพเช‚เชšเซ‹) เชธเชฟเชธเซเชŸเชฎ เช•เซ‰เชฒ accept() เชฅเซเชฐเซ‡เชก เชเช•เซเชเซ‡เช•เซเชฏเซเชถเชจ เช…เชŸเช•เชพเชตเซเชฏเซเช‚ เชจเชฅเซ€.
  • เชœเซ‹ reuse_port เชฌเชฐเชพเชฌเชฐ เช›เซ‡ true, เชชเช›เซ€ เช† เชซเช‚เช•เซเชถเชจ เชตเชฟเช•เชฒเซเชช เชธเชพเชฅเซ‡ เชธเซ‹เช•เซ‡เชŸเชจเซ‡ เช—เซ‹เช เชตเชถเซ‡ SO_REUSEPORT เชฆเซเชตเชพเชฐเชพ setsockopt()เชฎเชฒเซเชŸเซ€-เชฅเซเชฐเซ‡เชกเซ‡เชก เชเชจเซเชตเชพเชฏเชฐเซเชจเชฎเซ‡เชจเซเชŸเชฎเชพเช‚ เชธเชฎเชพเชจ เชชเซ‹เชฐเซเชŸเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ ("เชฎเชฒเซเชŸเชฟ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐ" เชตเชฟเชญเชพเช— เชœเซเช“).

เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐ on_accept() OS เช เช‡เชตเซ‡เชจเซเชŸ เชœเชจเชฐเซ‡เชŸ เช•เชฐเซ‡ เชคเซ‡ เชชเช›เซ€ เชฌเซ‹เชฒเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ EPOLLIN, เช† เช•เชฟเชธเซเชธเชพเชฎเชพเช‚ เชเชŸเชฒเซ‡ เช•เซ‡ เชจเชตเซเช‚ เชœเซ‹เชกเชพเชฃ เชธเซเชตเซ€เช•เชพเชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡. on_accept() เชจเชตเซเช‚ เช•เชจเซ‡เช•เซเชถเชจ เชธเซเชตเซ€เช•เชพเชฐเซ‡ เช›เซ‡, เชคเซ‡เชจเซ‡ เชจเซ‹เชจ-เชฌเซเชฒเซ‹เช•เชฟเช‚เช— เชฎเซ‹เชก เชชเชฐ เชธเซเชตเชฟเชš เช•เชฐเซ‡ เช›เซ‡ เช…เชจเซ‡ เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐ เชธเชพเชฅเซ‡ เชจเซ‹เช‚เชงเชฃเซ€ เช•เชฐเซ‡ เช›เซ‡ on_recv() I/O เชฐเชฟเชเช•เซเชŸเชฐเชฎเชพเช‚.

on_accept() เชซเช‚เช•เซเชถเชจ เชฌเชคเชพเชตเซ‹

static void on_accept(void *arg, int fd, uint32_t events) {
    int incoming_conn;
    SAFE_CALL((incoming_conn = accept(fd, NULL, NULL)), -1);
    set_nonblocking(incoming_conn);
    SAFE_CALL(reactor_register(reactor, incoming_conn, EPOLLIN, on_recv,
                               request_buffer_new()),
              -1);
}

เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐ on_recv() OS เช เช‡เชตเซ‡เชจเซเชŸ เชœเชจเชฐเซ‡เชŸ เช•เชฐเซ‡ เชคเซ‡ เชชเช›เซ€ เชฌเซ‹เชฒเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ EPOLLIN, เช† เช•เชฟเชธเซเชธเชพเชฎเชพเช‚ เชฎเชคเชฒเชฌ เช•เซ‡ เชœเซ‹เชกเชพเชฃ เชจเซ‹เช‚เชงเชพเชฏเซ‡เชฒ เช›เซ‡ on_accept(), เชกเซ‡เชŸเชพ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชคเซˆเชฏเชพเชฐ เช›เซ‡.

on_recv() เชœเซเชฏเชพเช‚ เชธเซเชงเซ€ HTTP เชตเชฟเชจเช‚เชคเซ€ เชธเช‚เชชเซ‚เชฐเซเชฃเชชเชฃเซ‡ เชชเซเชฐเชพเชชเซเชค เชจ เชฅเชพเชฏ เชคเซเชฏเชพเช‚ เชธเซเชงเซ€ เช•เชจเซ‡เช•เซเชถเชจเชฎเชพเช‚เชฅเซ€ เชกเซ‡เชŸเชพ เชตเชพเช‚เชšเซ‡ เช›เซ‡, เชชเช›เซ€ เชคเซ‡ เชนเซ‡เชจเซเชกเชฒเชฐเชจเซ€ เชจเซ‹เช‚เชงเชฃเซ€ เช•เชฐเซ‡ เช›เซ‡ on_send() HTTP เชชเซเชฐเชคเชฟเชธเชพเชฆ เชฎเซ‹เช•เชฒเชตเชพ เชฎเชพเชŸเซ‡. เชœเซ‹ เช•เซเชฒเชพเชฏเชจเซเชŸ เช•เชจเซ‡เช•เซเชถเชจ เชคเซ‹เชกเซ‡ เช›เซ‡, เชคเซ‹ เชธเซ‹เช•เซ‡เชŸเชจเซ€ เชจเซ‹เช‚เชงเชฃเซ€ เชฐเชฆ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ เช…เชจเซ‡ เชคเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชฌเช‚เชง เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ close().

เชซเช‚เช•เซเชถเชจ on_recv() เชฌเชคเชพเชตเซ‹

static void on_recv(void *arg, int fd, uint32_t events) {
    RequestBuffer *buffer = arg;

    // ะŸั€ะธะฝะธะผะฐะตะผ ะฒั…ะพะดะฝั‹ะต ะดะฐะฝะฝั‹ะต ะดะพ ั‚ะตั… ะฟะพั€, ั‡ั‚ะพ recv ะฒะพะทะฒั€ะฐั‚ะธั‚ 0 ะธะปะธ ะพัˆะธะฑะบัƒ
    ssize_t nread;
    while ((nread = recv(fd, buffer->data + buffer->size,
                         REQUEST_BUFFER_CAPACITY - buffer->size, 0)) > 0)
        buffer->size += nread;

    // ะšะปะธะตะฝั‚ ะพะฑะพั€ะฒะฐะป ัะพะตะดะธะฝะตะฝะธะต
    if (nread == 0) {
        SAFE_CALL(reactor_deregister(reactor, fd), -1);
        SAFE_CALL(close(fd), -1);
        request_buffer_destroy(buffer);
        return;
    }

    // read ะฒะตั€ะฝัƒะป ะพัˆะธะฑะบัƒ, ะพั‚ะปะธั‡ะฝัƒัŽ ะพั‚ ะพัˆะธะฑะบะธ, ะฟั€ะธ ะบะพั‚ะพั€ะพะน ะฒั‹ะทะพะฒ ะทะฐะฑะปะพะบะธั€ัƒะตั‚
    // ะฟะพั‚ะพะบ
    if (errno != EAGAIN && errno != EWOULDBLOCK) {
        request_buffer_destroy(buffer);
        fail("read");
    }

    // ะŸะพะปัƒั‡ะตะฝ ะฟะพะปะฝั‹ะน HTTP ะทะฐะฟั€ะพั ะพั‚ ะบะปะธะตะฝั‚ะฐ. ะขะตะฟะตั€ัŒ ั€ะตะณะธัั‚ั€ะธั€ัƒะตะผ ะพะฑั€ะฐะฑะพั‚ั‡ะธะบะฐ
    // ัะพะฑั‹ั‚ะธะน ะดะปั ะพั‚ะฟั€ะฐะฒะบะธ ะดะฐะฝะฝั‹ั…
    if (request_buffer_is_complete(buffer)) {
        request_buffer_clear(buffer);
        SAFE_CALL(reactor_reregister(reactor, fd, EPOLLOUT, on_send, buffer),
                  -1);
    }
}

เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐ on_send() OS เช เช‡เชตเซ‡เชจเซเชŸ เชœเชจเชฐเซ‡เชŸ เช•เชฐเซ‡ เชคเซ‡ เชชเช›เซ€ เชฌเซ‹เชฒเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ EPOLLOUT, เชเชŸเชฒเซ‡ เช•เซ‡ เช•เชจเซ‡เช•เซเชถเชจ เชจเซ‹เช‚เชงเชพเชฏเซ‡เชฒ เช›เซ‡ on_recv(), เชกเซ‡เชŸเชพ เชฎเซ‹เช•เชฒเชตเชพ เชฎเชพเชŸเซ‡ เชคเซˆเชฏเชพเชฐ เช›เซ‡. เช† เชซเช‚เช•เซเชถเชจ เช•เซเชฒเชพเชฏเช‚เชŸเชจเซ‡ เชˆเชฎเซ‡เชœ เชธเชพเชฅเซ‡ HTML เชงเชฐเชพเชตเชคเซ‹ HTTP เชชเซเชฐเชคเชฟเชธเชพเชฆ เชฎเซ‹เช•เชฒเซ‡ เช›เซ‡ เช…เชจเซ‡ เชชเช›เซ€ เชˆเชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐเชจเซ‡ เชชเชพเช›เซเช‚ เชฌเชฆเชฒเซ‡ เช›เซ‡ on_recv().

on_send() เชซเช‚เช•เซเชถเชจ เชฌเชคเชพเชตเซ‹

static void on_send(void *arg, int fd, uint32_t events) {
    const char *content = "<img "
                          "src="https://habrastorage.org/webt/oh/wl/23/"
                          "ohwl23va3b-dioerobq_mbx4xaw.jpeg">";
    char response[1024];
    sprintf(response,
            "HTTP/1.1 200 OK" CRLF "Content-Length: %zd" CRLF "Content-Type: "
            "text/html" DOUBLE_CRLF "%s",
            strlen(content), content);

    SAFE_CALL(send(fd, response, strlen(response), 0), -1);
    SAFE_CALL(reactor_reregister(reactor, fd, EPOLLIN, on_recv, arg), -1);
}

เช…เชจเซ‡ เช›เซ‡เชฒเซเชฒเซ‡, เชซเชพเช‡เชฒเชฎเชพเช‚ http_server.c, เช•เชพเชฐเซเชฏเชฎเชพเช‚ main() เช…เชฎเซ‡ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ I/O เชฐเชฟเชเช•เซเชŸเชฐ เชฌเชจเชพเชตเซ€เช เช›เซ€เช reactor_new(), เชธเชฐเซเชตเชฐ เชธเซ‹เช•เซ‡เชŸ เชฌเชจเชพเชตเซ‹ เช…เชจเซ‡ เชคเซ‡เชจเซ‡ เชฐเชœเซ€เชธเซเชŸเชฐ เช•เชฐเซ‹, เชคเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชฐเชฟเชเช•เซเชŸเชฐ เชถเชฐเซ‚ เช•เชฐเซ‹ reactor_run() เชฌเชฐเชพเชฌเชฐ เชเช• เชฎเชฟเชจเชฟเชŸ เชฎเชพเชŸเซ‡, เช…เชจเซ‡ เชชเช›เซ€ เช…เชฎเซ‡ เชธเช‚เชธเชพเชงเชจเซ‹ เชชเซเชฐเช•เชพเชถเชฟเชค เช•เชฐเซ€เช เช›เซ€เช เช…เชจเซ‡ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชฎเชพเช‚เชฅเซ€ เชฌเชนเชพเชฐ เชจเซ€เช•เชณเซ€เช เช›เซ€เช.

http_server.c เชฌเชคเชพเชตเซ‹

#include "reactor.h"

static Reactor *reactor;

#include "common.h"

int main(void) {
    SAFE_CALL((reactor = reactor_new()), NULL);
    SAFE_CALL(
        reactor_register(reactor, new_server(false), EPOLLIN, on_accept, NULL),
        -1);
    SAFE_CALL(reactor_run(reactor, SERVER_TIMEOUT_MILLIS), -1);
    SAFE_CALL(reactor_destroy(reactor), -1);
}

เชšเชพเชฒเซ‹ เชคเชชเชพเชธเซ€เช เช•เซ‡ เชฌเชงเซเช‚ เช…เชชเซ‡เช•เซเชทเชพ เชฎเซเชœเชฌ เช•เชพเชฐเซเชฏ เช•เชฐเซ€ เชฐเชนเซเชฏเซเช‚ เช›เซ‡. เชธเช‚เช•เชฒเชจ (chmod a+x compile.sh && ./compile.sh เชชเซเชฐเซ‹เชœเซ‡เช•เซเชŸ เชฐเซ‚เชŸเชฎเชพเช‚) เช…เชจเซ‡ เชธเซเชต-เชฒเซ‡เช–เชฟเชค เชธเชฐเซเชตเชฐ เชฒเซ‹เช‚เชš เช•เชฐเซ‹, เช–เซ‹เชฒเซ‹ http://127.0.0.1:18470 เชฌเซเชฐเชพเช‰เชเชฐเชฎเชพเช‚ เช…เชจเซ‡ เชœเซเช“ เช•เซ‡ เช…เชฎเซ‡ เชถเซเช‚ เช…เชชเซ‡เช•เซเชทเชพ เชฐเชพเช–เซ€เช เช›เซ€เช:

เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

เชชเซเชฐเชฆเชฐเซเชถเชจ เชฎเชพเชชเชจ

เชฎเชพเชฐเซ€ เช•เชพเชฐเชจเซ€ เชตเชฟเชถเชฟเชทเซเชŸเชคเชพเช“ เชฌเชคเชพเชตเซ‹

$ screenfetch
 MMMMMMMMMMMMMMMMMMMMMMMMMmds+.        OS: Mint 19.1 tessa
 MMm----::-://////////////oymNMd+`     Kernel: x86_64 Linux 4.15.0-20-generic
 MMd      /++                -sNMd:    Uptime: 2h 34m
 MMNso/`  dMM    `.::-. .-::.` .hMN:   Packages: 2217
 ddddMMh  dMM   :hNMNMNhNMNMNh: `NMm   Shell: bash 4.4.20
     NMm  dMM  .NMN/-+MMM+-/NMN` dMM   Resolution: 1920x1080
     NMm  dMM  -MMm  `MMM   dMM. dMM   DE: Cinnamon 4.0.10
     NMm  dMM  -MMm  `MMM   dMM. dMM   WM: Muffin
     NMm  dMM  .mmd  `mmm   yMM. dMM   WM Theme: Mint-Y-Dark (Mint-Y)
     NMm  dMM`  ..`   ...   ydm. dMM   GTK Theme: Mint-Y [GTK2/3]
     hMM- +MMd/-------...-:sdds  dMM   Icon Theme: Mint-Y
     -NMm- :hNMNNNmdddddddddy/`  dMM   Font: Noto Sans 9
      -dMNs-``-::::-------.``    dMM   CPU: Intel Core i7-6700 @ 8x 4GHz [52.0ยฐC]
       `/dMNmy+/:-------------:/yMMM   GPU: NV136
          ./ydNMMMMMMMMMMMMMMMMMMMMM   RAM: 2544MiB / 7926MiB
             .MMMMMMMMMMMMMMMMMMM

เชšเชพเชฒเซ‹ เชธเชฟเช‚เช—เชฒ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐเชจเซเช‚ เชชเซเชฐเชฆเชฐเซเชถเชจ เชฎเชพเชชเซ€เช. เชšเชพเชฒเซ‹ เชฌเซ‡ เชŸเชฐเซเชฎเชฟเชจเชฒ เช–เซ‹เชฒเซ€เช: เชเช•เชฎเชพเช‚ เช†เชชเชฃเซ‡ เชฆเซ‹เชกเซ€เชถเซเช‚ ./http_server, เชเช• เช…เชฒเช— เชฐเซ€เชคเซ‡ - เช•เชฐเซเช•. เชเช• เชฎเชฟเชจเชฟเชŸ เชชเช›เซ€, เชจเซ€เชšเซ‡เชจเชพ เช†เช‚เช•เชกเชพ เชฌเซ€เชœเชพ เชŸเชฐเซเชฎเชฟเชจเชฒเชฎเชพเช‚ เชชเซเชฐเชฆเชฐเซเชถเชฟเชค เชฅเชถเซ‡:

$ wrk -c100 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   493.52us   76.70us  17.31ms   89.57%
    Req/Sec    24.37k     1.81k   29.34k    68.13%
  11657769 requests in 1.00m, 1.60GB read
Requests/sec: 193974.70
Transfer/sec:     27.19MB

เช…เชฎเชพเชฐเซเช‚ เชธเชฟเช‚เช—เชฒ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐ 11 เช•เชจเซ‡เช•เซเชถเชจเซเชธเชฎเชพเช‚เชฅเซ€ เช‰เชฆเซเชญเชตเชคเชพ เชชเซเชฐเชคเชฟ เชฎเชฟเชจเชฟเชŸ 100 เชฎเชฟเชฒเชฟเชฏเชจเชฅเซ€ เชตเชงเซ เชตเชฟเชจเช‚เชคเซ€เช“ เชชเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชตเชพเชฎเชพเช‚ เชธเช•เซเชทเชฎ เชนเชคเซเช‚. เช–เชฐเชพเชฌ เชชเชฐเชฟเชฃเชพเชฎ เชจเชฅเซ€, เชชเชฐเช‚เชคเซ เชถเซเช‚ เชคเซ‡ เชธเซเชงเชพเชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡?

เชฎเชฒเซเชŸเชฟเชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐ

เช‰เชชเชฐ เชœเชฃเชพเชตเซเชฏเชพ เชฎเซเชœเชฌ, I/O เชฐเชฟเชเช•เซเชŸเชฐ เช…เชฒเช— เชฅเซเชฐเซ‡เชกเซ‹เชฎเชพเช‚ เชฌเชจเชพเชตเซ€ เชถเช•เชพเชฏ เช›เซ‡, เชคเซเชฏเชพเช‚ เชคเชฎเชพเชฎ CPU เช•เซ‹เชฐเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡. เชšเชพเชฒเซ‹ เช† เช…เชญเชฟเช—เชฎเชจเซ‡ เชตเซเชฏเชตเชนเชพเชฐเชฎเชพเช‚ เชฎเซ‚เช•เซ€เช:

http_server_multithreaded.c เชฌเชคเชพเชตเซ‹

#include "reactor.h"

static Reactor *reactor;
#pragma omp threadprivate(reactor)

#include "common.h"

int main(void) {
#pragma omp parallel
    {
        SAFE_CALL((reactor = reactor_new()), NULL);
        SAFE_CALL(reactor_register(reactor, new_server(true), EPOLLIN,
                                   on_accept, NULL),
                  -1);
        SAFE_CALL(reactor_run(reactor, SERVER_TIMEOUT_MILLIS), -1);
        SAFE_CALL(reactor_destroy(reactor), -1);
    }
}

เชนเชตเซ‡ เชฆเชฐเซ‡เช• เชฅเซเชฐเซ‡เชก เชชเซ‹เชคเชพเชจเซ€ เชฎเชพเชฒเชฟเช•เซ€ เชงเชฐเชพเชตเซ‡ เช›เซ‡ เชฐเชฟเชเช•เซเชŸเชฐ

static Reactor *reactor;
#pragma omp threadprivate(reactor)

เชฎเชนเซ‡เชฐเชฌเชพเชจเซ€ เช•เชฐเซ€เชจเซ‡ เชจเซ‹เช‚เชง เช•เชฐเซ‹ เช•เซ‡ เช•เชพเชฐเซเชฏ เชฆเชฒเซ€เชฒ new_server() เชนเชฟเชฎเชพเชฏเชค true. เช†เชจเซ‹ เช…เชฐเซเชฅ เช เช›เซ‡ เช•เซ‡ เช…เชฎเซ‡ เชธเชฐเซเชตเชฐ เชธเซ‹เช•เซ‡เชŸเชจเซ‡ เชตเชฟเช•เชฒเซเชช เชธเซ‹เช‚เชชเซ€เช เช›เซ€เช SO_REUSEPORTเชฌเชนเซ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชตเชพเชคเชพเชตเชฐเชฃเชฎเชพเช‚ เชคเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡. เชคเชฎเซ‡ เชตเชงเซ เชตเชฟเช—เชคเซ‹ เชตเชพเช‚เชšเซ€ เชถเช•เซ‹ เช›เซ‹ เช…เชนเซ€เช‚.

เชฌเซ€เชœเซ€ เชฆเซ‹เชก

เชนเชตเซ‡ เชšเชพเชฒเซ‹ เชฎเชฒเซเชŸเชฟ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเชฐเซเชตเชฐเชจเซเช‚ เชชเซเชฐเชฆเชฐเซเชถเชจ เชฎเชพเชชเซ€เช:

$ wrk -c100 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.14ms    2.53ms  40.73ms   89.98%
    Req/Sec    79.98k    18.07k  154.64k    78.65%
  38208400 requests in 1.00m, 5.23GB read
Requests/sec: 635876.41
Transfer/sec:     89.14MB

1 เชฎเชฟเชจเชฟเชŸเชฎเชพเช‚ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชพเชฏเซ‡เชฒเซ€ เชตเชฟเชจเช‚เชคเซ€เช“เชจเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ ~3.28 เช—เชฃเซ‹ เชตเชงเชพเชฐเซ‹ เชฅเชฏเซ‹ เช›เซ‡! เชชเชฐเช‚เชคเซ เช…เชฎเซ‡ เชฐเชพเช‰เชจเซเชก เชจเช‚เชฌเชฐเชฅเซ€ เชฎเชพเชคเซเชฐ ~XNUMX เชฎเชฟเชฒเชฟเชฏเชจ เช“เช›เชพ เชนเชคเชพ, เชคเซ‡เชฅเซ€ เชšเชพเชฒเซ‹ เชคเซ‡เชจเซ‡ เช เซ€เช• เช•เชฐเชตเชพเชจเซ‹ เชชเซเชฐเชฏเชพเชธ เช•เชฐเซ€เช.

เชชเชนเซ‡เชฒเชพ เช†เชชเชฃเซ‡ เชœเชจเชฐเซ‡เชŸ เชฅเชฏเซ‡เชฒเชพ เช†เช‚เช•เชกเชพ เชœเซ‹เชˆเช เชชเชฐเชซ:

$ sudo perf stat -B -e task-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,branches,branch-misses,cache-misses ./http_server_multithreaded

 Performance counter stats for './http_server_multithreaded':

     242446,314933      task-clock (msec)         #    4,000 CPUs utilized          
         1โ€ฏ813โ€ฏ074      context-switches          #    0,007 M/sec                  
             4โ€ฏ689      cpu-migrations            #    0,019 K/sec                  
               254      page-faults               #    0,001 K/sec                  
   895โ€ฏ324โ€ฏ830โ€ฏ170      cycles                    #    3,693 GHz                    
   621โ€ฏ378โ€ฏ066โ€ฏ808      instructions              #    0,69  insn per cycle         
   119โ€ฏ926โ€ฏ709โ€ฏ370      branches                  #  494,653 M/sec                  
     3โ€ฏ227โ€ฏ095โ€ฏ669      branch-misses             #    2,69% of all branches        
           808โ€ฏ664      cache-misses                                                

      60,604330670 seconds time elapsed

CPU เชเชซเชฟเชจเชฟเชŸเซ€เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเซ‹, เชธเชพเชฅเซ‡ เชธเช‚เช•เชฒเชจ -march=native, เชชเซ€เชœเซ€เช“, เชนเชฟเชŸเชจเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ เชตเชงเชพเชฐเซ‹ เช•เซ‡เชถ, เชตเชงเชพเชฐเซ‹ MAX_EVENTS เช…เชจเซ‡ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‹ EPOLLET เช•เชพเชฎเช—เซ€เชฐเซ€เชฎเชพเช‚ เชจเซ‹เช‚เชงเชชเชพเชคเซเชฐ เชตเชงเชพเชฐเซ‹ เชฅเชฏเซ‹ เชจเชฅเซ€. เชชเชฐเช‚เชคเซ เชœเซ‹ เชคเชฎเซ‡ เชเช• เชธเชพเชฅเซ‡ เชœเซ‹เชกเชพเชฃเซ‹เชจเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ เชตเชงเชพเชฐเซ‹ เช•เชฐเซ‹ เชคเซ‹ เชถเซเช‚ เชฅเชถเซ‡?

352 เชเช• เชธเชพเชฅเซ‡ เชœเซ‹เชกเชพเชฃเซ‹ เชฎเชพเชŸเซ‡ เช†เช‚เช•เชกเชพ:

$ wrk -c352 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
  8 threads and 352 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.12ms    3.79ms  68.23ms   87.49%
    Req/Sec    83.78k    12.69k  169.81k    83.59%
  40006142 requests in 1.00m, 5.48GB read
Requests/sec: 665789.26
Transfer/sec:     93.34MB

เช‡เชšเซเช›เชฟเชค เชชเชฐเชฟเชฃเชพเชฎ เชชเซเชฐเชพเชชเซเชค เชฅเชฏเซเช‚ เชนเชคเซเช‚, เช…เชจเซ‡ เชคเซ‡เชจเซ€ เชธเชพเชฅเซ‡ เช•เชจเซ‡เช•เซเชถเชจเซเชธเชจเซ€ เชธเช‚เช–เซเชฏเชพ เชชเชฐ 1 เชฎเชฟเชจเชฟเชŸเชฎเชพเช‚ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเซ‡เชฒเซ€ เชตเชฟเชจเช‚เชคเซ€เช“เชจเซ€ เชธเช‚เช–เซเชฏเชพเชจเซ€ เช…เชตเชฒเช‚เชฌเชจ เชฆเชฐเซเชถเชพเชตเชคเซ‹ เชเช• เชฐเชธเชชเซเชฐเชฆ เช—เซเชฐเชพเชซ:

เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเซเชตเชฟเชงเชพเชฏเซเช•เซเชค เชฌเซ‡เชฐ-เชธเซ€ I/O เชฐเชฟเชเช•เซเชŸเชฐ

เช…เชฎเซ‡ เชœเซ‹เชˆเช เช›เซ€เช เช•เซ‡ เชฌเซ‡ เชธเซ‹ เช•เชจเซ‡เช•เซเชถเชจเซเชธ เชชเช›เซ€, เชฌเช‚เชจเซ‡ เชธเชฐเซเชตเชฐเซเชธ เชฎเชพเชŸเซ‡เชจเซ€ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเซ‡เชฒเซ€ เชตเชฟเชจเช‚เชคเซ€เช“เชจเซ€ เชธเช‚เช–เซเชฏเชพ เชเชกเชชเชฅเซ€ เช˜เชŸเซ€ เชœเชพเชฏ เช›เซ‡ (เชฎเชฒเซเชŸเซ€-เชฅเซเชฐเซ‡เชกเซ‡เชก เชธเช‚เชธเซเช•เชฐเชฃเชฎเชพเช‚ เช† เชตเชงเซ เชงเซเชฏเชพเชจเชชเชพเชคเซเชฐ เช›เซ‡). เชถเซเช‚ เช† Linux TCP/IP เชธเซเชŸเซ‡เช• เช…เชฎเชฒเซ€เช•เชฐเชฃ เชธเชพเชฅเซ‡ เชธเช‚เชฌเช‚เชงเชฟเชค เช›เซ‡? เชŸเชฟเชชเซเชชเชฃเซ€เช“เชฎเชพเช‚ เช—เซเชฐเชพเชซเชจเซ€ เช† เชตเชฐเซเชคเชฃเซ‚เช• เช…เชจเซ‡ เชฎเชฒเซเชŸเชฟ-เชฅเซเชฐเซ‡เชกเซ‡เชก เช…เชจเซ‡ เชธเชฟเช‚เช—เชฒ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชตเชฟเช•เชฒเซเชชเซ‹ เชฎเชพเชŸเซ‡ เช‘เชชเซเชŸเชฟเชฎเชพเช‡เชเซ‡เชถเชจ เชตเชฟเชถเซ‡ เชคเชฎเชพเชฐเซ€ เชงเชพเชฐเชฃเชพเช“ เชฒเช–เชตเชพ เชฎเชพเชŸเซ‡ เชจเชฟเชƒเชธเช‚เช•เซ‹เชš.

เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เชจเซ‹เช‚เชงเซเชฏเซเช‚ เชŸเชฟเชชเซเชชเชฃเซ€เช“เชฎเชพเช‚, เช† เชชเซเชฐเชฆเชฐเซเชถเชจ เชชเชฐเซ€เช•เซเชทเชฃ เชตเชพเชธเซเชคเชตเชฟเช• เชฒเซ‹เชก เชนเซ‡เช เชณ I/O เชฐเชฟเชเช•เซเชŸเชฐเชจเซเช‚ เชตเชฐเซเชคเชจ เชฌเชคเชพเชตเชคเซเช‚ เชจเชฅเซ€, เช•เชพเชฐเชฃ เช•เซ‡ เชฒเช—เชญเช— เชนเช‚เชฎเซ‡เชถเชพ เชธเชฐเซเชตเชฐ เชกเซ‡เชŸเชพเชฌเซ‡เช เชธเชพเชฅเซ‡ เช•เซเชฐเชฟเชฏเชพเชชเซเชฐเชคเชฟเช•เซเชฐเชฟเชฏเชพ เช•เชฐเซ‡ เช›เซ‡, เชฒเซ‹เช— เช†เช‰เชŸเชชเซเชŸ เช•เชฐเซ‡ เช›เซ‡, เช•เซเชฐเชฟเชชเซเชŸเซ‹เช—เซเชฐเชพเชซเซ€เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‡ เช›เซ‡ TLS เชตเช—เซ‡เชฐเซ‡, เชœเซ‡เชจเชพ เชชเชฐเชฟเชฃเชพเชฎเซ‡ เชญเชพเชฐ เชฌเชฟเชจ-เชฏเซเชจเชฟเชซเซ‹เชฐเซเชฎ (เช—เชคเชฟเชถเซ€เชฒ) เชฌเชจเซ‡ เช›เซ‡. I/O เชชเซเชฐเซ‹เชเช•เซเชŸเชฐ เชตเชฟเชถเซ‡เชจเชพ เชฒเซ‡เช–เชฎเชพเช‚ เชคเซƒเชคเซ€เชฏ-เชชเช•เซเชท เช˜เชŸเช•เซ‹ เชธเชพเชฅเซ‡ เชชเชฐเซ€เช•เซเชทเชฃเซ‹ เชนเชพเชฅ เชงเชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡.

I/O เชฐเชฟเชเช•เซเชŸเชฐเชจเชพ เช—เซ‡เชฐเชซเชพเชฏเชฆเชพ

เชคเชฎเชพเชฐเซ‡ เช เชธเชฎเชœเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡ เช•เซ‡ I/O เชฐเชฟเชเช•เซเชŸเชฐ เชคเซ‡เชจเซ€ เช–เชพเชฎเซ€เช“ เชตเชฟเชจเชพ เชจเชฅเซ€, เชเชŸเชฒเซ‡ เช•เซ‡:

  • เชฎเชฒเซเชŸเชฟ-เชฅเซเชฐเซ‡เชกเซ‡เชก เชตเชพเชคเชพเชตเชฐเชฃเชฎเชพเช‚ I/O เชฐเชฟเชเช•เซเชŸเชฐเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเซ‹ เช•เช‚เชˆเช• เชตเชงเซ เชฎเซเชถเซเช•เซ‡เชฒ เช›เซ‡, เช•เชพเชฐเชฃ เช•เซ‡ เชคเชฎเชพเชฐเซ‡ เชชเซเชฐเชตเชพเชนเซ‹เชจเซเช‚ เชธเช‚เชšเชพเชฒเชจ เชœเชพเชคเซ‡ เช•เชฐเชตเซเช‚ เชชเชกเชถเซ‡.
  • เชชเซเชฐเซ‡เช•เซเชŸเชฟเชธ เชฌเชคเชพเชตเซ‡ เช›เซ‡ เช•เซ‡ เชฎเซ‹เชŸเชพ เชญเชพเช—เชจเชพ เช•เชฟเชธเซเชธเชพเช“เชฎเชพเช‚ เชฒเซ‹เชก เชฌเชฟเชจ-เชธเชฎเชพเชจ เชนเซ‹เชฏ เช›เซ‡, เชœเซ‡ เชเช• เชฅเซเชฐเซ‡เชก เชฒเซ‹เช—เชฟเช‚เช— เชคเชฐเชซ เชฆเซ‹เชฐเซ€ เชถเช•เซ‡ เช›เซ‡ เชœเซเชฏเชพเชฐเซ‡ เชฌเซ€เชœเซ‹ เช•เชพเชฎเชฎเชพเช‚ เชตเซเชฏเชธเซเชค เชนเซ‹เชฏ เช›เซ‡.
  • เชœเซ‹ เชเช• เช‡เชตเซ‡เชจเซเชŸ เชนเซ‡เชจเซเชกเชฒเชฐ เชฅเซเชฐเซ‡เชกเชจเซ‡ เช…เชตเชฐเซ‹เชงเชฟเชค เช•เชฐเซ‡ เช›เซ‡, เชคเซ‹ เชธเชฟเชธเซเชŸเชฎ เชชเชธเช‚เชฆเช—เซ€เช•เชพเชฐ เชชเซ‹เชคเซ‡ เชชเชฃ เช…เชตเชฐเซ‹เชงเชฟเชค เช•เชฐเชถเซ‡, เชœเซ‡ เชถเซ‹เชงเชตเชพเชฎเชพเช‚ เชฎเซเชถเซเช•เซ‡เชฒ เชฌเช— เชคเชฐเชซ เชฆเซ‹เชฐเซ€ เชถเช•เซ‡ เช›เซ‡.

เช† เชธเชฎเชธเซเชฏเชพเช“ เช‰เช•เซ‡เชฒเซ‡ เช›เซ‡ I/O เชชเซเชฐเซ‹เชเช•เซเชŸเชฐ, เชœเซ‡เชฎเชพเช‚ เช˜เชฃเซ€เชตเชพเชฐ เชถเซ‡เชกเซเชฏเซ‚เชฒเชฐ เชนเซ‹เชฏ เช›เซ‡ เชœเซ‡ เชฒเซ‹เชกเชจเซ‡ เชฅเซเชฐเซ‡เชกเซ‹เชจเชพ เชชเซ‚เชฒ เชชเชฐ เชธเชฎเชพเชจเชฐเซ‚เชชเซ‡ เชตเชฟเชคเชฐเชฟเชค เช•เชฐเซ‡ เช›เซ‡, เช…เชจเซ‡ เชคเซ‡ เชตเชงเซ เช…เชจเซเช•เซ‚เชณ API เชชเชฃ เชงเชฐเชพเชตเซ‡ เช›เซ‡. เช…เชฎเซ‡ เชคเซ‡เชจเชพ เชตเชฟเชถเซ‡ เชชเช›เซ€เชฅเซ€ เชฎเชพเชฐเชพ เช…เชจเซเชฏ เชฒเซ‡เช–เชฎเชพเช‚ เชตเชพเชค เช•เชฐเซ€เชถเซเช‚.

เชจเชฟเชทเซเช•เชฐเซเชท

เช† เชคเซ‡ เช›เซ‡ เชœเซเชฏเชพเช‚ เชธเชฟเชฆเซเชงเชพเช‚เชคเชฅเซ€ เชธเซ€เชงเชพ เชชเซเชฐเซ‹เชซเชพเช‡เชฒเชฐ เชเช•เซเชเซ‹เชธเซเชŸ เชธเซเชงเซ€เชจเซ€ เช…เชฎเชพเชฐเซ€ เชธเชซเชฐ เชธเชฎเชพเชชเซเชค เชฅเชˆ เช›เซ‡.

เชคเชฎเชพเชฐเซ‡ เช†เชจเชพ เชชเชฐ เชงเซเชฏเชพเชจ เช†เชชเชตเซเช‚ เชœเซ‹เชˆเช เชจเชนเซ€เช‚, เช•เชพเชฐเชฃ เช•เซ‡ เชธเช—เชตเชก เช…เชจเซ‡ เชเชกเชชเชจเชพ เชตเชฟเชตเชฟเชง เชธเซเชคเชฐเซ‹ เชธเชพเชฅเซ‡ เชจเซ‡เชŸเชตเชฐเซเช• เชธเซ‰เชซเซเชŸเชตเซ‡เชฐ เชฒเช–เชตเชพ เชฎเชพเชŸเซ‡ เช…เชจเซเชฏ เช˜เชฃเชพ เชธเชฎเชพเชจ เชฐเชธเชชเซเชฐเชฆ เช…เชญเชฟเช—เชฎเซ‹ เช›เซ‡. เชฐเชธเชชเซเชฐเชฆ, เชฎเชพเชฐเชพ เชฎเชคเซ‡, เชฒเชฟเช‚เช•เซเชธ เชจเซ€เชšเซ‡ เช†เชชเซ‡เชฒ เช›เซ‡.

เชคเชฎเชจเซ‡ เชซเชฐเซ€ เชฎเชฒเซ€เชธเซ!

เชฐเชธเชชเซเชฐเชฆ เชชเซเชฐเซ‹เชœเซ‡เช•เซเชŸเซเชธ

เชฌเซ€เชœเซเช‚ เชถเซเช‚ เชตเชพเช‚เชšเชตเซเช‚?

เชธเซ‹เชฐเซเชธ: www.habr.com

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹