рдкреВрд░реНрдг рд╡реИрд╢рд┐рд╖реНрдЯреНрдпреАрдХреГрдд рдмреЗрдЕрд░-рд╕реА I/O рдЕрдгреБрднрдЯреНрдЯреА

рдкреВрд░реНрдг рд╡реИрд╢рд┐рд╖реНрдЯреНрдпреАрдХреГрдд рдмреЗрдЕрд░-рд╕реА I/O рдЕрдгреБрднрдЯреНрдЯреА

рдкрд░рд┐рдЪрдп

I/O рдЕрдгреБрднрдЯреНрдЯреА (рд╕рд┐рдВрдЧрд▓ рдереНрд░реЗрдбреЗрдб рдЗрд╡реНрд╣реЗрдВрдЯ рд▓реВрдк) рд╣рд╛ рдЙрдЪреНрдЪ-рд▓реЛрдб рд╕реЙрдлреНрдЯрд╡реЗрдЕрд░ рд▓рд┐рд╣рд┐рдгреНрдпрд╛рд╕рд╛рдареА рдПрдХ рдирдореБрдирд╛ рдЖрд╣реЗ, рдЬреЛ рдЕрдиреЗрдХ рд▓реЛрдХрдкреНрд░рд┐рдп рдЙрдкрд╛рдпрд╛рдВрдордзреНрдпреЗ рд╡рд╛рдкрд░рд▓рд╛ рдЬрд╛рддреЛ:

рдпрд╛ рд▓реЗрдЦрд╛рдд, рдЖрдореНрд╣реА I/O рдЕрдгреБрднрдЯреНрдЯреАрдЪреЗ рдЗрдиреНрд╕ рдЖрдгрд┐ рдЖрдЙрдЯреНрд╕ рдкрд╛рд╣реВ рдЖрдгрд┐ рддреЗ рдХрд╕реЗ рдХрд╛рд░реНрдп рдХрд░рддреЗ, рдХреЛрдбрдЪреНрдпрд╛ 200 рдкреЗрдХреНрд╖рд╛ рдХрдореА рдУрд│реАрдВрдордзреНрдпреЗ рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА рд▓рд┐рд╣реВ рдЖрдгрд┐ 40 рджрд╢рд▓рдХреНрд╖ рд╡рд┐рдирдВрддреНрдпрд╛/рдорд┐рдирд┐рдЯрд╛рдВрдкреЗрдХреНрд╖рд╛ рдПрдХ рд╕рд╛рдзреА HTTP рд╕рд░реНрд╡реНрд╣рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░реВ.

рдкреНрд░рд╕реНрддрд╛рд╡рдирд╛

  • рд╣рд╛ рд▓реЗрдЦ I/O рдЕрдгреБрднрдЯреНрдЯреАрдЪреА рдХрд╛рд░реНрдпрдкреНрд░рдгрд╛рд▓реА рд╕рдордЬреВрди рдШреЗрдгреНрдпрд╛рдд рдорджрдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЖрдгрд┐ рддреНрдпрд╛рдореБрд│реЗ рддреЗ рд╡рд╛рдкрд░рддрд╛рдирд╛ рдЬреЛрдЦреАрдо рд╕рдордЬреВрди рдШреЗрдгреНрдпрд╛рд╕рд╛рдареА рд▓рд┐рд╣рд┐рд▓рд╛ рдЧреЗрд▓рд╛ рдЖрд╣реЗ.
  • рд▓реЗрдЦ рд╕рдордЬреВрди рдШреЗрдгреНрдпрд╛рд╕рд╛рдареА рдореВрд▓рднреВрдд рдЧреЛрд╖реНрдЯреАрдВрдЪреЗ рдЬреНрдЮрд╛рди рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ. рд╕реА рднрд╛рд╖рд╛ рдЖрдгрд┐ рдиреЗрдЯрд╡рд░реНрдХ рдНрдкреНрд▓рд┐рдХреЗрд╢рди рдбреЗрд╡реНрд╣рд▓рдкрдореЗрдВрдЯрдордзреАрд▓ рдХрд╛рд╣реА рдЕрдиреБрднрд╡.
  • рд╕рд░реНрд╡ рдХреЛрдб C рднрд╛рд╖реЗрдд рдХрд╛рдЯреЗрдХреЛрд░рдкрдгреЗ (рдЦрдмрд░рджрд╛рд░реА: рд▓рд╛рдВрдм PDF) C11 рдорд╛рдирдХрд╛рдкрд░реНрдпрдВрдд Linux рд╕рд╛рдареА рдЖрдгрд┐ рд╡рд░ рдЙрдкрд▓рдмреНрдз GitHub.

рд╣реЗ рдЖрд╡рд╢реНрдпрдХ рдХрд╛ рдЖрд╣реЗ?

рдЗрдВрдЯрд░рдиреЗрдЯрдЪреНрдпрд╛ рд╡рд╛рдврддреНрдпрд╛ рд▓реЛрдХрдкреНрд░рд┐рдпрддреЗрд╕рд╣, рд╡реЗрдм рд╕рд░реНрд╡реНрд╣рд░рд▓рд╛ рдПрдХрд╛рдЪ рд╡реЗрд│реА рдореЛрдареНрдпрд╛ рд╕рдВрдЦреНрдпреЗрдиреЗ рдХрдиреЗрдХреНрд╢рди рд╣рд╛рддрд╛рд│рдгреНрдпрд╛рдЪреА рдЧрд░рдЬ рднрд╛рд╕реВ рд▓рд╛рдЧрд▓реА рдЖрдгрд┐ рдореНрд╣рдгреВрди рджреЛрди рдкрджреНрдзрддреА рд╡рд╛рдкрд░рд▓реНрдпрд╛ рдЧреЗрд▓реНрдпрд╛: рдореЛрдареНрдпрд╛ рд╕рдВрдЦреНрдпреЗрдиреЗ OS рдереНрд░реЗрдбреНрд╕рд╡рд░ I/O рд▓рд╛ рдмреНрд▓реЙрдХ рдХрд░рдгреЗ рдЖрдгрд┐ I/O рд▓рд╛ рдмреНрд▓реЙрдХ рди рдХрд░рдгреЗ. рдЗрд╡реНрд╣реЗрдВрдЯ рд╕реВрдЪрдирд╛ рдкреНрд░рдгрд╛рд▓реА, рдЬреНрдпрд╛рд▓рд╛ "рд╕рд┐рд╕реНрдЯрдо рд╕рд┐рд▓реЗрдХреНрдЯрд░" рджреЗрдЦреАрд▓ рдореНрд╣рдгрддрд╛рдд (epoll/kqueue/IOCP/ рдЗрддреНрдпрд╛рджреА).

рдкреНрд░рддреНрдпреЗрдХ рдЗрдирдХрдорд┐рдВрдЧ рдХрдиреЗрдХреНрд╢рдирд╕рд╛рдареА рдирд╡реАрди OS рдереНрд░реЗрдб рддрдпрд╛рд░ рдХрд░рдгреЗ рд╣рд╛ рдкрд╣рд┐рд▓рд╛ рджреГрд╖реНрдЯрд┐рдХреЛрди рдЖрд╣реЗ. рддреНрдпрд╛рдЪреЗ рдиреБрдХрд╕рд╛рди рдЦрд░рд╛рдм рд╕реНрдХреЗрд▓реЗрдмрд┐рд▓рд┐рдЯреА рдЖрд╣реЗ: рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдорд▓рд╛ рдЕрдиреЗрдХ рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА рдХрд░рд╛рд╡реА рд▓рд╛рдЧреЗрд▓ рд╕рдВрджрд░реНрдн рд╕рдВрдХреНрд░рдордгреЗ ╨╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓. рддреЗ рдорд╣рд╛рдЧ рдСрдкрд░реЗрд╢рдиреНрд╕ рдЖрд╣реЗрдд рдЖрдгрд┐ рдкреНрд░рднрд╛рд╡реА рдХрдиреЗрдХреНрд╢рдирд╕рд╣ рд╡рд┐рдирд╛рдореВрд▓реНрдп рд░реЕрдордЪреА рдХрдорддрд░рддрд╛ рд╣реЛрдК рд╢рдХрддреЗ.

рд╕реБрдзрд╛рд░рд┐рдд рдЖрд╡реГрддреНрддреА рд╣рд╛рдпрд▓рд╛рдЗрдЯ рдХрд░рддреЗ рдереНрд░реЗрдбреНрд╕рдЪреА рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ (рдереНрд░реЗрдб рдкреВрд▓), рдЬреНрдпрд╛рдореБрд│реЗ рд╕рд┐рд╕реНрдЯрдорд▓рд╛ рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА рд░рджреНрдж рдХрд░рдгреНрдпрд╛рдкрд╛рд╕реВрди рдкреНрд░рддрд┐рдмрдВрдзрд┐рдд рдХрд░рддреЗ, рдкрд░рдВрддреБ рддреНрдпрд╛рдЪ рд╡реЗрд│реА рдПрдХ рдирд╡реАрди рд╕рдорд╕реНрдпрд╛ рд╕рд╛рджрд░ рдХрд░рддреЗ: рдЬрд░ рдереНрд░реЗрдб рдкреВрд▓ рд╕рдзреНрдпрд╛ рджреАрд░реНрдШ рд╡рд╛рдЪрди рдСрдкрд░реЗрд╢рдиреНрд╕рджреНрд╡рд╛рд░реЗ рдЕрд╡рд░реЛрдзрд┐рдд рдХреЗрд▓рд╛ рдЕрд╕реЗрд▓, рддрд░ рдЗрддрд░ рд╕реЙрдХреЗрдЯреНрд╕ рдЬреЗ рдЖрдзреАрдЪ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдгреНрдпрд╛рд╕ рд╕рдХреНрд╖рдо рдЕрд╕рддреАрд▓. рддрд╕реЗ рдХрд░рд╛

рджреБрд╕рд░рд╛ рджреГрд╖реНрдЯрд┐рдХреЛрди рд╡рд╛рдкрд░рддреЛ рдХрд╛рд░реНрдпрдХреНрд░рдо рд╕реВрдЪрдирд╛ рдкреНрд░рдгрд╛рд▓реА (рд╕рд┐рд╕реНрдЯрдо рд╕рд┐рд▓реЗрдХреНрдЯрд░) OS рджреНрд╡рд╛рд░реЗ рдкреНрд░рджрд╛рди рдХреЗрд▓реЗ рдЬрд╛рддреЗ. рд╣рд╛ рд▓реЗрдЦ I/O рдСрдкрд░реЗрд╢рдиреНрд╕рд╕рд╛рдареА рддрддреНрдкрд░рддреЗрдмрджреНрджрд▓ рд╕реВрдЪрдирд╛ (рдЗрд╡реНрд╣реЗрдВрдЯ, рдиреЛрдЯрд┐рдлрд┐рдХреЗрд╢рди) рд╡рд░ рдЖрдзрд╛рд░рд┐рдд рд╕рд┐рд╕реНрдЯреАрдо рд╕рд┐рд▓реЗрдХреНрдЯрд░рдЪреНрдпрд╛ рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдХрд╛рд░рд╛рд╡рд░ рдЪрд░реНрдЪрд╛ рдХрд░рддреЛ. рддреНрдпрд╛рдВрдЪреНрдпрд╛ рдкреВрд░реНрдгрддреЗрдмрджреНрджрд▓ рд╕реВрдЪрдирд╛. рддреНрдпрд╛рдЪреНрдпрд╛ рд╡рд╛рдкрд░рд╛рдЪреЗ рд╕рд░рд▓реАрдХреГрдд рдЙрджрд╛рд╣рд░рдг рдЦрд╛рд▓реАрд▓ рдмреНрд▓реЙрдХ рдЖрдХреГрддреАрджреНрд╡рд╛рд░реЗ рджрд░реНрд╢рд╡рд┐рд▓реЗ рдЬрд╛рдК рд╢рдХрддреЗ:

рдкреВрд░реНрдг рд╡реИрд╢рд┐рд╖реНрдЯреНрдпреАрдХреГрдд рдмреЗрдЕрд░-рд╕реА I/O рдЕрдгреБрднрдЯреНрдЯреА

рдпрд╛ рдкрджреНрдзрддреАрдВрдордзреАрд▓ рдлрд░рдХ рдЦрд╛рд▓реАрд▓рдкреНрд░рдорд╛рдгреЗ рдЖрд╣реЗ:

  • I/O рдСрдкрд░реЗрд╢рдиреНрд╕ рдЕрд╡рд░реЛрдзрд┐рдд рдХрд░рдгреЗ рдирд┐рд▓рдВрдмрд┐рдд рд╡рд╛рдкрд░рдХрд░реНрддрд╛ рдкреНрд░рд╡рд╛рд╣ рдкрд░реНрдпрдВрддOS рд╡реНрдпрд╡рд╕реНрдерд┐рдд рд╣реЛрдИрдкрд░реНрдпрдВрдд рдбреАрдлреНрд░реЕрдЧрдореЗрдВрдЯ рдпреЗрдгрд╛рд░реЗ рдЖрдпрдкреА рдкреЕрдХреЗрдЯреНрд╕ рдкреНрд░рд╡рд╛рд╣ рдмрд╛рдЗрдЯ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА (рдЯреАрд╕реАрдкреА, рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдд рдЖрд╣реЗ) рдХрд┐рдВрд╡рд╛ рддреНрдпрд╛рдирдВрддрд░рдЪреНрдпрд╛ рджреНрд╡рд╛рд░реЗ рдкрд╛рдард╡рдгреНрдпрд╛рдХрд░рд┐рддрд╛ рдЕрдВрддрд░реНрдЧрдд рд▓реЗрдЦрди рдмрдлрд░рдордзреНрдпреЗ рдкреБрд░реЗрд╢реА рдЬрд╛рдЧрд╛ рдЙрдкрд▓рдмреНрдз рдирд╕реЗрд▓ рдХрд╛рд╣реАрд╣реА рдирд╛рд╣реА (рдбреЗрдЯрд╛ рдкрд╛рдард╡рдд рдЖрд╣реЗ).
  • рд╕рд┐рд╕реНрдЯрдо рдирд┐рд╡рдбрдХрд░реНрддрд╛ рдЬрд╛рджрд╛ рд╡реЗрд│ рдкреНрд░реЛрдЧреНрд░рд╛рдорд▓рд╛ рд╕реВрдЪрд┐рдд рдХрд░рддреЗ рдХреА 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 рдЦрд╛рд▓реАрд▓ рдШреЛрд╖рдгрд╛рдВрдЪрд╛ рд╕рдорд╛рд╡реЗрд╢ рдЕрд╕реЗрд▓:

рдЕрдгреБрднрдЯреНрдЯреАрдордзреНрдпреЗ рдШреЛрд╖рдгрд╛ рджрд░реНрд╢рд╡рд╛

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 рдЕрдгреБрднрдЯреНрдЯреАрдЪреА рд░рдЪрдирд╛ рдЕрд╕рддреЗ рдлрд╛рдЗрд▓ рд╡рд░реНрдгрдирдХрд░реНрддрд╛ рдирд┐рд╡рдбрдХрд░реНрддрд╛ epoll ╨╕ рд╣реЕрд╢ рдЯреЗрдмрд▓ 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.

reactor_run() рдлрдВрдХреНрд╢рди рджрд╛рдЦрд╡рд╛

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, рдЬреНрдпрд╛рдордзреНрдпреЗ рдЦрд╛рд▓реАрд▓ рдлрдВрдХреНрд╢рди рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдЖрд╣реЗрдд:

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╛