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

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

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

I/O рд░рд┐рдПрдХреНрдЯрд░ (рдПрдХрд▓ рдереНрд░реЗрдбреЗрдб рдШрдЯрдирд╛ рд▓реВрдк) рдЙрдЪреНрдЪ-рд▓реЛрдб рд╕рдлреНрдЯрд╡реЗрдпрд░ рд▓реЗрдЦреНрдирдХреЛ рд▓рд╛рдЧрд┐ рдПрдХ рдврд╛рдБрдЪрд╛ рд╣реЛ, рдзреЗрд░реИ рд▓реЛрдХрдкреНрд░рд┐рдп рд╕рдорд╛рдзрд╛рдирд╣рд░реВрдорд╛ рдкреНрд░рдпреЛрдЧ рдЧрд░рд┐рдиреНрдЫ:

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

Foreword

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

рдпреЛ рдХрд┐рди рдЖрд╡рд╢реНрдпрдХ рдЫ?

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

рдкрд╣рд┐рд▓реЛ рджреГрд╖реНрдЯрд┐рдХреЛрдгрд▓реЗ рдкреНрд░рддреНрдпреЗрдХ рдЖрдЧрдорди рдЬрдбрд╛рдирдХреЛ рд▓рд╛рдЧрд┐ рдирдпрд╛рдБ OS рдереНрд░реЗрдб рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрдиреЗ рд╕рдорд╛рд╡реЗрд╢ рдЧрд░реНрджрдЫред рдпрд╕рдХреЛ рдмреЗрдлрд╛рдЗрджрд╛ рдЦрд░рд╛рдм рд╕реНрдХреЗрд▓реЗрдмрд┐рд▓рд┐рдЯреА рд╣реЛ: рдЕрдкрд░реЗрдЯрд┐рдЩ рд╕рд┐рд╕реНрдЯрдорд▓реЗ рдзреЗрд░реИ рд▓рд╛рдЧреВ рдЧрд░реНрдиреБрдкрд░реНрдиреЗрдЫ рд╕рдиреНрджрд░реНрдн рд╕рдВрдХреНрд░рдордг ╨╕ рдкреНрд░рдгрд╛рд▓реА рдХрд▓рд╣рд░реВред рддрд┐рдиреАрд╣рд░реВ рдорд╣рдБрдЧреЛ рдЕрдкрд░реЗрд╢рдирд╣рд░реВ рд╣реБрдиреН рд░ рдЬрдбрд╛рдирд╣рд░реВрдХреЛ рдкреНрд░рднрд╛рд╡рд╢рд╛рд▓реА рд╕рдВрдЦреНрдпрд╛рдХреЛ рд╕рд╛рде рдирд┐: рд╢реБрд▓реНрдХ RAM рдХреЛ рдЕрднрд╛рд╡ рд╣реБрди рд╕рдХреНрдЫред

рдкрд░рд┐рдорд╛рд░реНрдЬрд┐рдд рд╕рдВрд╕реНрдХрд░рдг рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдЧрд░реНрджрдЫ рдереНрд░реЗрдбрд╣рд░реВрдХреЛ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ (рдереНрд░реЗрдб рдкреВрд▓), рдЬрд╕рд▓реЗ рдкреНрд░рдгрд╛рд▓реАрд▓рд╛рдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд░реЛрдХреНрдирдмрд╛рдЯ рд░реЛрдХреНрдЫ, рддрд░ рдПрдХреИ рд╕рдордпрдорд╛ рдирдпрд╛рдБ рд╕рдорд╕реНрдпрд╛рдХреЛ рдкрд░рд┐рдЪрдп рджрд┐рдБрджреИ: рдпрджрд┐ рдереНрд░реЗрдб рдкреВрд▓ рд╣рд╛рд▓ рд▓рд╛рдореЛ рдкрдвреНрдиреЗ рдЕрдкрд░реЗрд╕рдирд╣рд░реВрджреНрд╡рд╛рд░рд╛ рдЕрд╡рд░реБрджреНрдз рдЫ рднрдиреЗ, рдЕрдиреНрдп рд╕рдХреЗрдЯрд╣рд░реВ рдЬреБрди рдкрд╣рд┐рд▓реЗ рдиреИ рдбрд╛рдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрди рд╕рдХреНрд╖рдо рд╣реБрдиреЗрдЫреИрдирдиреНред рддреЗрд╕реЛ рдЧрд░ред

рджреЛрд╕реНрд░реЛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрдЫ рдШрдЯрдирд╛ рд╕реВрдЪрдирд╛ рдкреНрд░рдгрд╛рд▓реА (рдкреНрд░рдгрд╛рд▓реА рдЪрдпрдирдХрд░реНрддрд╛) OS рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдЧрд░рд┐рдПрдХреЛред рдпрд╕ рд▓реЗрдЦрд▓реЗ I/O рдЕрдкрд░реЗрд╕рдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рддрдпрд╛рд░реАрдХреЛ рдмрд╛рд░реЗрдорд╛ рдЕрд▓рд░реНрдЯрд╣рд░реВ (рдШрдЯрдирд╛рд╣рд░реВ, рд╕реВрдЪрдирд╛рд╣рд░реВ) рдорд╛ рдЖрдзрд╛рд░рд┐рдд рдкреНрд░рдгрд╛рд▓реА рдЪрдпрдирдХрд░реНрддрд╛рдХреЛ рд╕рдмреИрднрдиреНрджрд╛ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдХрд╛рд░рдХреЛ рдмрд╛рд░реЗрдорд╛ рдЫрд▓рдлрд▓ рдЧрд░реНрджрдЫред рддрд┐рдиреАрд╣рд░реВрдХреЛ рдкреВрд░рд╛ рдмрд╛рд░реЗ рд╕реВрдЪрдирд╛рд╣рд░реВред рдпрд╕рдХреЛ рдкреНрд░рдпреЛрдЧрдХреЛ рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рдирд┐рдореНрди рдмреНрд▓рдХ рд░реЗрдЦрд╛рдЪрд┐рддреНрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫ:

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

рдпреА рджреГрд╖реНрдЯрд┐рдХреЛрдгрд╣рд░реВ рдмреАрдЪрдХреЛ рднрд┐рдиреНрдирддрд╛ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдЫ:

  • I/O рдХрд╛рд░реНрдпрд╣рд░реВ рдЕрд╡рд░реБрджреНрдз рдЧрд░реНрджреИ рдирд┐рд▓рдореНрдмрди рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░рд╡рд╛рд╣ рд╕рдореНрдордУрдПрд╕ рдареАрдХрд╕рдБрдЧ рдирднрдПрд╕рдореНрдо defragments рдЖрдЧрдорди рдЖрдИрдкреА тАЛтАЛрдкреНрдпрд╛рдХреЗрдЯрд╣рд░реВ рдмрд╛рдЗрдЯ рд╕реНрдЯреНрд░рд┐рдо рдЧрд░реНрди (рдЯреАрд╕реАрдкреА, рдбрд╛рдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрджреИ) рд╡рд╛ рддреНрдпрд╕рдкрдЫрд┐рдХреЛ рдорд╛рдзреНрдпрдордмрд╛рдЯ рдкрдард╛рдЙрдирдХреЛ рд▓рд╛рдЧрд┐ рдЖрдиреНрддрд░рд┐рдХ рд▓реЗрдЦрди рдмрдлрд░рд╣рд░реВрдорд╛ рдкрд░реНрдпрд╛рдкреНрдд рдард╛рдЙрдБ рдЙрдкрд▓рдмреНрдз рд╣реБрдиреЗрдЫреИрдиред рдПрдирдЖрдИрд╕реА (рдбреЗрдЯрд╛ рдкрдард╛рдЙрдБрджреИ)ред
  • рдкреНрд░рдгрд╛рд▓реА рдЪрдпрдирдХрд░реНрддрд╛ рд╕рдордпрдХреЛ рдХреНрд░рдорд╕рдБрдЧреИ рдХрд╛рд░реНрдпрдХреНрд░рдорд▓рд╛рдИ рд╕реВрдЪрд┐рдд рдЧрд░реНрджрдЫ рдХрд┐ OS рдкрд╣рд┐рд▓реЗ рдиреИ рдбрд┐рдлреНрд░реЗрдЧреНрдореЗрдиреНрдЯреЗрдб рдЖрдИрдкреА рдкреНрдпрд╛рдХреЗрдЯрд╣рд░реВ (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, рд░ in 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 рдорд┐рд▓рд┐рдпрди рдорд╛рддреНрд░ рдЫреЛрдЯреЛ рдерд┐рдпреМрдВ, рддреНрдпрд╕реИрд▓реЗ рдпрд╕рд▓рд╛рдИ рдареАрдХ рдЧрд░реНрдиреЗ рдкреНрд░рдпрд╛рд╕ рдЧрд░реМрдВред

рдкрд╣рд┐рд▓реЗ рдЙрддреНрдкрдиреНрди рддрдереНрдпрд╛рдЩреНрдХ рд╣реЗрд░реМрдВ perf:

$ 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 рд░рд┐рдПрдХреНрдЯрд░

рд╣рд╛рдореА рджреЗрдЦреНрдЫреМрдВ рдХрд┐ рд╕рдпреМрдВ рдЬрдбрд╛рдирд╣рд░реВ рдкрдЫрд┐, рджреБрдмреИ рд╕рд░реНрднрд░рд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рдкреНрд░рд╢реЛрдзрд┐рдд рдЕрдиреБрд░реЛрдзрд╣рд░реВрдХреЛ рд╕рдВрдЦреНрдпрд╛ рджреНрд░реБрдд рд░реВрдкрдорд╛ рдШрдЯреНрдЫ (рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб рд╕рдВрд╕реНрдХрд░рдгрдорд╛ рдпреЛ рдЕрдзрд┐рдХ рдзреНрдпрд╛рди рджрд┐рди рдпреЛрдЧреНрдп рдЫ)ред рдХреЗ рдпреЛ рд▓рд┐рдирдХреНрд╕ TCP/IP рд╕реНрдЯреНрдпрд╛рдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирд╕рдБрдЧ рд╕рдореНрдмрдиреНрдзрд┐рдд рдЫ? рдЯрд┐рдкреНрдкрдгреАрд╣рд░реВрдорд╛ рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб рд░ рдПрдХрд▓-рдереНрд░реЗрдбреЗрдб рд╡рд┐рдХрд▓реНрдкрд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рдЧреНрд░рд╛рдл рд░ рдЕрдкреНрдЯрд┐рдорд╛рдЗрдЬреЗрд╕рдирдХреЛ рдпрд╕ рд╡реНрдпрд╡рд╣рд╛рд░рдХреЛ рдмрд╛рд░реЗрдорд╛ рдЖрдлреНрдиреЛ рдЕрдиреБрдорд╛рдирд╣рд░реВ рд▓реЗрдЦреНрди рд╕реНрд╡рддрдиреНрддреНрд░ рдорд╣рд╕реБрд╕ рдЧрд░реНрдиреБрд╣реЛрд╕реНред

рдХрд╕рд░реА рдиреЛрдЯ рдЧрд░рд┐рдпреЛ рдЯрд┐рдкреНрдкрдгреАрд╣рд░реВрдорд╛, рдпреЛ рдХрд╛рд░реНрдпрд╕рдореНрдкрд╛рджрди рдкрд░реАрдХреНрд╖рдгрд▓реЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд▓реЛрдбрд╣рд░реВ рдЕрдиреНрддрд░реНрдЧрдд I/O рд░рд┐рдПрдХреНрдЯрд░рдХреЛ рд╡реНрдпрд╡рд╣рд╛рд░ рджреЗрдЦрд╛рдЙрдБрджреИрди, рдХрд┐рдирдХрд┐ рд▓рдЧрднрдЧ рд╕рдзреИрдБ рд╕рд░реНрднрд░рд▓реЗ рдбрд╛рдЯрд╛рдмреЗрд╕рд╕рдБрдЧ рдЕрдиреНрддрд░рдХреНрд░рд┐рдпрд╛ рдЧрд░реНрдЫ, рд▓рдЧрд╣рд░реВ рдЖрдЙрдЯрдкреБрдЯ рдЧрд░реНрджрдЫ, рдХреНрд░рд┐рдкреНрдЯреЛрдЧреНрд░рд╛рдлреА рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрдЫред TLS рдЖрджрд┐, рдЬрд╕рдХреЛ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рд▓реЛрдб рдЧреИрд░-рдПрдХрд╕рдорд╛рди (рдЧрддрд┐рд╢реАрд▓) рд╣реБрдиреНрдЫред рддреЗрд╕реНрд░реЛ-рдкрдХреНрд╖ рдХрдореНрдкреЛрдиреЗрдиреНрдЯрд╣рд░реВрд╕рдБрдЧ рдкрд░реАрдХреНрд╖рдгрд╣рд░реВ I/O рдкреНрд░реЛрдПрдХреНрдЯрд░рдХреЛ рдмрд╛рд░реЗрдорд╛ рд▓реЗрдЦрдорд╛ рдЧрд░рд┐рдиреЗрдЫред

I/O рд░рд┐рдПрдХреНрдЯрд░рдХреЛ рдмреЗрдлрд╛рдЗрджрд╛рд╣рд░реВ

рддрдкрд╛рдИрд▓реЗ рдмреБрдЭреНрдиреБ рдЖрд╡рд╢реНрдпрдХ рдЫ рдХрд┐ I/O рд░рд┐рдПрдХреНрдЯрд░ рдпрд╕рдХреЛ рдХрдордЬреЛрд░реА рдмрд┐рдирд╛ рдЫреИрди, рдЕрд░реНрдерд╛рддреН:

  • рдмрд╣реБ-рдереНрд░реЗрдб рдЧрд░рд┐рдПрдХреЛ рд╡рд╛рддрд╛рд╡рд░рдгрдорд╛ I/O рд░рд┐рдПрдХреНрдЯрд░ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБ рдЕрд▓рд┐ рдмрдвреА рдЧрд╛рд╣реНрд░реЛ рдЫ, рдХрд┐рдирднрдиреЗ рддрдкрд╛рдИрдВрд▓реЗ рдкреНрд░рд╡рд╛рд╣рд╣рд░реВ рдореНрдпрд╛рдиреБрдЕрд▓ рд░реВрдкрдорд╛ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрди рдЧрд░реНрдиреБрдкрд░реНрдиреЗрдЫред
  • рдЕрднреНрдпрд╛рд╕рд▓реЗ рджреЗрдЦрд╛рдЙрдБрдЫ рдХрд┐ рдзреЗрд░реИрдЬрд╕реЛ рдЕрд╡рд╕реНрдерд╛рдорд╛ рд▓реЛрдб рдЧреИрд░-рдПрдХрд╕рдорд╛рди рд╣реБрдиреНрдЫ, рдЬрд╕рд▓реЗ рдЧрд░реНрджрд╛ рдПрдЙрдЯрд╛ рдереНрд░реЗрдб рд▓рдЧрд┐рдЩ рд╣реБрди рд╕рдХреНрдЫ рдЬрдмрдХрд┐ рдЕрд░реНрдХреЛ рдХрд╛рдордорд╛ рд╡реНрдпрд╕реНрдд рд╣реБрдиреНрдЫред
  • рдпрджрд┐ рдПрдХ рдШрдЯрдирд╛ рд╣реНрдпрд╛рдиреНрдбрд▓рд░рд▓реЗ рдереНрд░реЗрдб рдмреНрд▓рдХ рдЧрд░реНрдЫ рднрдиреЗ, рдкреНрд░рдгрд╛рд▓реА рдЪрдпрдирдХрд░реНрддрд╛рд▓реЗ рдкрдирд┐ рдмреНрд▓рдХ рдЧрд░реНрдиреЗрдЫ, рдЬрд╕рд▓реЗ рдмрдЧрд╣рд░реВ рдлреЗрд▓рд╛ рдкрд╛рд░реНрди рдЧрд╛рд╣реНрд░реЛ рд╣реБрди рд╕рдХреНрдЫред

рдпреА рд╕рдорд╕реНрдпрд╛рд╣рд░реВ рд╕рдорд╛рдзрд╛рди рдЧрд░реНрдЫ I/O рдкреНрд░реЛрдПрдХреНрдЯрд░, рдЬрд╕рдорд╛ рдкреНрд░рд╛рдпрдГ рдПрдХ рд╢реЗрдбреНрдпреБрд▓рд░ рд╣реБрдиреНрдЫ рдЬрд╕рд▓реЗ рд▓реЛрдбрд▓рд╛рдИ рдереНрд░реЗрдбрдХреЛ рдкреВрд▓рдорд╛ рд╕рдорд╛рди рд░реВрдкрдорд╛ рд╡рд┐рддрд░рдг рдЧрд░реНрджрдЫ, рд░ рдердк рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ API рдкрдирд┐ рдЫред рд╣рд╛рдореА рдпрд╕рдХреЛ рдмрд╛рд░реЗрдорд╛ рдкрдЫрд┐ рдХреБрд░рд╛ рдЧрд░реНрдиреЗрдЫреМрдВ, рдореЗрд░реЛ рдЕрд░реНрдХреЛ рд▓реЗрдЦрдорд╛ред

рдирд┐рд╖реНрдХрд░реНрд╖рдорд╛

рд╕рд┐рджреНрдзрд╛рдиреНрддрдмрд╛рдЯ рд╕реАрдзрд╛ рдкреНрд░реЛрдлрд╛рдЗрд▓рд░ рдирд┐рдХрд╛рд╕рд╕рдореНрдордХреЛ рд╣рд╛рдореНрд░реЛ рдпрд╛рддреНрд░рд╛ рдпрд╣реАрдБрдмрд╛рдЯ рд╕рдорд╛рдкреНрдд рднрдПрдХреЛ рдЫред

рддрдкрд╛рдИрд▓реЗ рдпрд╕рдорд╛ рдзреНрдпрд╛рди рджрд┐рдиреБ рд╣реБрдБрджреИрди, рдХрд┐рдирдХрд┐ рддреНрдпрд╣рд╛рдБ рд╡рд┐рднрд┐рдиреНрди рд╕реНрддрд░рдХреЛ рд╕реБрд╡рд┐рдзрд╛ рд░ рдЧрддрд┐рдХреЛ рд╕рд╛рде рдиреЗрдЯрд╡рд░реНрдХ рд╕рдлреНрдЯрд╡реЗрдпрд░ рд▓реЗрдЦреНрдирдХреЛ рд▓рд╛рдЧрд┐ рдзреЗрд░реИ рдЕрдиреНрдп рд╕рдорд╛рди рд░реВрдкрдорд╛ рд░реЛрдЪрдХ рджреГрд╖реНрдЯрд┐рдХреЛрдгрд╣рд░реВ рдЫрдиреНред рдЪрд╛рдЦрд▓рд╛рдЧреНрджреЛ, рдореЗрд░реЛ рд╡рд┐рдЪрд╛рд░рдорд╛, рд▓рд┐рдЩреНрдХрд╣рд░реВ рддрд▓ рджрд┐рдЗрдПрдХреЛ рдЫред

рдЕрд░реНрдХреЛ рд╕рдордп рд╕рдореНрдо!

рд░реЛрдЪрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛рд╣рд░реВ

рдореИрд▓реЗ рдЕрд░реВ рдХреЗ рдкрдвреНрдиреБ рдкрд░реНрдЫ?

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди