ááá¢á«
á áá áœáá ááµá¥ ášI/O á¬á áá°áá á¥á á¥ááŽáµ á¥áá°áá°á« á¥áááášá³ááá£áš200 á£áá° ášá®áµ ááµáá áµáá á«á á¥áá áááá£á¥á ááá ášá€áœá²á²á á áááá áá°áµ áš40 ááá®á á áá á¥á«áááœ/á°áá á¥áá°á«ááá¢
áá áµá
- áœáá ášá°á»áá áš I/O á¬á áá°áá á°áá£á ááášá³áµ á¥áá²ášá³ ááᣠá¥á áµááá á¥á±á á²á áá áµáá¶áœá ááášá³áµá¢
- áœááá ááášá³áµ áµá áá°ášá³á ááá®áœ á¥áááµ á«áµáááá.
á ááá á¥á á á áá³áš áášá¥ áá°áá áªá« áááµ ááµá¥ ášá°áá°á áááµá¢ - ááá á®áµ ášá°ááá á C ááá áá (á )á¥ááá: ášá
á áá²á€á)
áá° C11 áá°á á áááááµ á¥á á áá ááááá¢ášááá .
áá á áµááá ášááá ááááµá áá?
ášá áááášá¥ á°áá³á
ááµ á¥ášášááš á ááá£á± ášáµá á áááá®áœ á¥á ááááá¶áœá á á ááµ áá ááµá°áááµ áá᩠ᣠá¥á áµáááá áááµ á áá«ášáŠáœ á°ááášáá- I/Oá á á áá«á³ ášáµááá° ááá áá®áœ áá áááµ á¥á I/Oá áš áá á áá£áá ášááµá°áµ áá³ááá« áµáááµá£ á¥áá²áá âášáµáááµ áá«áâ á°á¥áá áá á«á (
ášááááªá«á á áá«ášá¥ áá¥á«áá³áá± áᢠáááááµ á á²áµ áµááá° ááá ááá áá á«á«áµá³áᢠáá³á± á°á«á áá á-á°á áá-áµááá° áááá á¥áááœá áá°áá á á áá áµá¢
ášá°á»á»áá á¥áµá á«á°ááá
ááá°áá áᎠáá ááá
á á¥ááá ááŽáᜠáá«ášá á«áá áá©ááµ á¥áá°áášá°áá áá.
- ášI/O áµá«ááœá áááµ áááµ ášá°á áá áá°áµ áµášáµáµááá° áááá á áµááá á¥áµáªá°á« áµášáµ
áá áážáµ áá¢ášá áá áá¬á¶áœ áá° á£ááµ á¥ášáµ (TCP ᣠáášá ááá á) ááá ááá£á á ááá áááá á ááµá¥ áá»áá« áá¶áœ ááµá¥ á á áŠá³ á ááááá¢ááá ááá (áášá á ááá áá)ᢠ- ášáµáááµ áá«á á°ášá᪠á°á áµ áµááá° áááá ááá®áá«á á«á³ááá áá ášá°á áá¹ ášá áá á¥á áᜠ(TCPᣠášááᥠááá á«) ááá á ááµá£á áá»áá« áá¶áœ ááµá¥ á á áŠá³ áá áááá (ááᥠááá).
ááá ááá á«á
á áá¥á«áá³áá± I/O ášáµááá° áááá áá ááášáµ ášá®ááá©á°á áááá áá£ášá ááᣠáááá«á±á á¥áá° á¥ááá± ášáá áá®á¹ á áá áµá«ááœá á¥ášá°á© á áá°áá (áµááá
áá
I/O á¬á áá°á ááŽá
áš I/O á¬á áá°á á áµáááµ áá«á á¥á á á°á áá á®áµ áá«ášá á¥áá° áá¥áá¥á áá áá°á«áᢠášá á á«á© ááá á áášá°áá ášááá ááµá á°ááá¿á.
- á ááµ ááµá°áµ á ááµ ášá°áá°á á¶á¬áµ ášáá«ááµ ášá á/አáŠáá¬áœá áášááá á¥áá°ááœá áá³ááá« áááá ááµá³ááµáá¢
- ášááµá°áµ á°áá£á£áª á ááµ ááµá°áµ á²á°ááµ á I/O á¬á áá°á ášáá á« á°áá£á ááᣠášáá«á ášáá«ááµ ášI/O áááá á«ášááááá¢
áš I/O á¬á áá°á á áµááá áá á-áá áááá áᥠáááµ á«áµááááᣠááá áá áá³á¡ á£áá¥á-áá á á«á£á¢ á 1 áá á¥ááá³ 1 á¬á áá°áᣠá áá á áááá ášá²áá© á®á®áœ á¥áá°áá á¥á á áá ášááá ášáá«áá°á ááá ááá ášááá¢
áµáá á«
ááá á áááá¹á á ááá ááµá¥ á¥ááµááá£ááᢠ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
(ášááµá°áµ á°áá£á£áª ááá
á á¥á áá¥á± ášá°á áá áááá)á¢
Reactor á¥á CallbackData á á³á
struct reactor {
int epoll_fd;
GHashTable *table; // (int, CallbackData)
};
typedef struct {
Callback callback;
void *arg;
} CallbackData;
á¥á£ááá ášááá£á á áœáá³á á¥áá°ááá á«áµá°áá reactor.h
á áááá©á á¥ááááá reactor
á¥á ááµá¥ reactor.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;
}
ááá ááá á á°á áá á®áµ ááµá¥ á«áá ášá°áá£á á¥áªáᜠá°áá°ááµ ášáášá°ááá á ᜠáááµá³áá¢
áá á áá á áááá
á ášáá°á áááµ ááµá¥ á«ááá ášá á/አá¬á áá°áá áááášáᣠáááááá á¥á«á á ááµá ášááááµ ááá ášá€áœá²á²á áᥠá°áášá á¥ááœáááá¢
áá€áœá²á²á áá®á¶á®á áá£á áá£áá»
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/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
(ášáááá» ášááᥠá áááµ).<ÐÐÐÐЫÐ>
- á á°á ááá ášá°á ášá ááá¥. á á¥á áá᳠ᣠáá° ááµá ášáááµá°á ááááµ áá ááá¢á€áœá²á€áá€á .
ááá http_server.c
common.h
ášá°áá£á áá®á¶á³ááá á áá« á á³á.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 reactor ááµá¥á¢
on_á°áá á() á°áá£á á á³á
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()
ášá€áœá²á²á á¥á«á áá á áá á¥áµáªáá á áµášáµ ášááááá± ášá°áááá áášá á«áá£áᣠášáá« á°áá£á£áª ááááá£á on_send()
ášá€áœá²á²á ááᜠááááᢠá°áá áá ááááá±á á«áášá , á¶á¬á± áá°ášáá á¥á á°á á
á áááá close()
á°áá£á á _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()
, ááᥠáááá ááá. áá
á°áá£á á€áœá²á²á€áá€áá ášá«á ááµá áá°áá áá ááá«á á¥á ášáá« ášááµá°áµ á°áá£á£áªáá áá° áá áááá áá 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 á¥ááá¥á«áá 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
á áá®áááµ áµá) á¥á á á«áµ ášá°á»ááá á áááá á«áµááá©, áááá±
ášá áá»ážá áááªá«
ášááªáá¬á áááááᜠá á³á
$ 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 reactor á á°ááš áá®áœ ááµá¥ ááá á ááœáá, á áá á áááá ášá²áá© á®áá¶áœ áá ááá. áá á á á«ááµ áá° á°áá£á á¥ááááá¡-
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
-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 á°áá ááµá¥ ášá°ášááá á¥á«ááᜠá¥ááµ á ááááá¶áœ á¥ááµ áá á¥áá áááá ášáá«á³á á áµá°á³áœ áá«áá¢
ášá ááµ áááµ áᶠááááá¶áœ á áá ášááá±á á áááá®áœ ášá°áµá°á«ášá á¥á«ááᜠáá¥á á ášáá°á ááá³ á¥ášááá° áááá á¥áá«áá (á á£áá¥á áá áµáªáµ ááµá¥ áá ášá áá ášáá³á áá)ᢠáá ášááááµ TCP/IP ááá áµáá á« áá ášá°á«á«á áá? áµááá ášáá«á á£á ᪠á¥á áá áµá°á«ášá¶áœ á£áá¥á-áá á¥á áá á-áá á áá«á®áœ ááá»ážáµ ášá¥ááµáá ááá¶áœ áááá ááááµ áá°ááá¢
á¥ááŽáµ
áš I/O á¬á áá°á áá³á¶áœ
áš I/O á¬á áá°á ášáµááá¶á¹ áá á¥áá³ááá áášá³áµ á ááŠáµá¡-
- á£áá¥á-áá á á«á£á¢ ááµá¥ I/O á¬á áá°á áá áá á á°áá°á á°ášá á áµážá᪠ááᣠáááá«á±á áá°á¶á¹á á¥á«áµá ááµá°á³á°á á áá¥ááµ.
- ááááµ á¥áá°áá«á³ášá á á á¥áááá¹ ááá³áᜠážáá áᥠá«ááá áá, áá á áá° á ááµ áá ááá£áµá áá«áᣠááœáá, áááá á°áá á áµá« ášá°á áá° áá.
- á ááµ ášááµá°áµ á°áá£á£áª ááá ášášáášáᣠášáµáááµ áá«á© á«á± á¥áá²á á«áá³áᣠáá á°áá áááááµ á áµážá᪠ášáá áµá á°á¶áœá á«áµášáµááá¢
á¥ááá
á áœáá®áœ ááá³á
áá°áá°áá«
ášá²á᪠á áá¥á³ áá° áá®áááá ááµ ááá« áááœá á«á áá á¥áá áá ááá¢
á áá áá áá°á®á ášáá¥ááµá ᣠáááá«á±á ášááµááá á¶ááµáá®áœá á á°áá«á© ášááŸáµ á¥á ášáá¥ááµ á°ášááᜠáááá ááᜠá¥á á¥á©á á áµá°á³áœ á áá«ášáŠáœ á áᢠášááááá, á á¥á á áµá°á«ášáµ, á áááᜠášáá á á³áœ á°á°á¥á°áá.
á á áá¡ á¥áááá!
á áµá°á³áœ áá®ááá¶áœ
- á²
áááµ
áá áá ááá ᥠá áá¥á?
https://linux.die.net/man/7/socket https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism http://www.kegel.com/c10k.html https://kernel.dk/io_uring.pdf https://aturon.github.io/blog/2016/09/07/futures-design/ https://tokio.rs/blog/2019-10-scheduler/ https://www.artima.com/articles/io_design_patterns.html https://habr.com/en/post/183832/
ááá: hab.com