แจแแกแแแแแ
แแ แกแขแแขแแแจแ แฉแแแ แแแแแแฎแแแแแ I/O แ แแแฅแขแแ แแก แฌแแแแแแก แแ แฌแแแแแแก แแ แ แแแแ แแฃแจแแแแก แแแ, แแแแฌแแ แ แแแแแแแแแขแแชแแแก แแแแแก 200 แกแขแ แแฅแแแแ แแแแแแ แฎแแแจแ แแ แแแแแแฃแจแแแแแ แแแ แขแแ HTTP แกแแ แแแ แก 40 แแแแแแ แแแแฎแแแแแแ/แฌแ.
แฌแแแแกแแขแงแแแแแ
- แกแขแแขแแ แแแแฌแแ แ แแแแกแแแแก, แ แแ แแแแแแแ I/O แ แแแฅแขแแ แแก แคแฃแแฅแชแแแแแ แแแ แแ, แจแแกแแแแแแกแแ, แแแแแแแ แ แแกแแแแ แแแกแ แแแแแงแแแแแแกแแก.
- แกแขแแขแแแก แแแกแแแแแแ แกแแญแแ แแ แกแแคแฃแซแแแแแแก แชแแแแ.
C แแแ แแ แแแ แแแแฃแแ แแแแแชแแแแแแ แฅแกแแแแก แแแแแแแชแแแแแก แจแแแฃแจแแแแแแจแ. - แงแแแแ แแแแ แแแฌแแ แแแแ C แแแแแ แแแแชแ แแ (แกแแคแ แแฎแแแ: แแ แซแแแ PDF)
C11 แกแขแแแแแ แขแแ Linux-แแกแแแแก แแ แฎแแแแแกแแฌแแแแแแGitHub .
แ แแขแแ แแแแแแแแ แแแแก?
แแแขแแ แแแขแแก แแแแ แแ แแแแฃแแแ แแแแ, แแแ แกแแ แแแ แแแก แกแญแแ แแแแแแแ แแ แแแ แแฃแแแ แแแแ แ แแแแแแแแแ แแแแจแแ แแแแก แแแแฃแจแแแแแ แแ, แจแแกแแแแแแกแแ, แกแชแแแแก แแ แ แแแแแแแ: I/O-แก แแแแแแแแ แแแแ แแชแแฃแแ แกแแกแขแแแแก แแแ แ แแแแแแแแแแ แแ I/O-แก แแแฃแแแแแแแ แแแแแแแแชแแแ. แแแแแแแแก แจแแขแงแแแแแแแแแแก แกแแกแขแแแ, แ แแแแแกแแช แแกแแแ แฃแฌแแแแแแ "แกแแกแขแแแแก แแแแแ แฉแแแแแก" (
แแแ แแแแ แแแแแแแ แแแแชแแแแ แแฎแแแ OS แซแแคแแก แจแแฅแแแแก แงแแแแแ แจแแแแแแแแแ แแแแจแแ แแกแแแแก. แแแกแ แแแแฃแกแ แแ แแก แชแฃแแ แแแกแจแขแแแแ แแแ: แแแแ แแชแแฃแ แกแแกแขแแแแก แแแฃแฌแแแก แแแแ แแก แแแแแ แแแ
แจแแชแแแแแ แแแ แกแแ แฎแแแก แฃแกแแแแก
แแแแ แ แแแแแแแ แแงแแแแแก
แแแแกแฎแแแแแแ แแ แแแแแแแแแก แจแแ แแก แจแแแแแแแ:
- I/O แแแแ แแชแแแแแก แแแแแแ แแแ แจแแแฉแแ แแก แแแแฎแแแ แแแแแก แแแแแแ แแแแแแแแกแแแแ OS แแแแแ แแฃแแแ
แแแคแ แแแแแแขแแแ แจแแแแแแแแแIP แแแแแขแแแ แแแแขแแก แแแแแแแ (TCP , แแแแแชแแแแแแก แแแฆแแแ) แแ แแ แแฅแแแแ แกแแแแแ แแกแ แแแแแแ แฉแแฌแแ แแก แจแแแ แแฃแคแแ แแแจแ แจแแแแแแแ แแแแแแแแแกแแแแกNIC (แแแแแชแแแแแแก แแแแแแแแ). - แกแแกแขแแแแก แแแแแ แฉแแแ แแ แแแก แแแแแแแแแแแจแ แแชแแแแแแก แแ แแแ แแแแก, แ แแ OS แฃแแแ แแแคแ แแแแแแขแแ แแแฃแแ IP แแแแแขแแแ (TCP, แแแแแชแแแแ แแแฆแแแ) แแ แกแแแแแ แแกแ แแแแแแ แฉแแฌแแ แแก แจแแแ แแฃแคแแ แแแจแ แฃแแแ แฎแแแแแกแแฌแแแแแ (แแแแแชแแแแแแก แแแแแแแแ).
แ แแ แจแแแแฏแแแแ, OS-แแก แซแแคแแแแก แแแฏแแแจแแ แแแแแแฃแแ I/O-แกแแแแก แแ แแก แแแแแแแแแแ แกแแแซแแแแ แแก แแแแแ แแแ, แ แแแแแ แกแแแแแแแแแแจแ, แซแแคแแแ แแ แแกแ แฃแแแแแ แกแแกแแ แแแแแ แกแแแฃแจแแแก (แแฅแแแแ แแแแแก แแก แขแแ แแแแ
I/O แ แแแฅแขแแ แแก แแแแแแ
I/O แ แแแฅแขแแ แ แแแฅแแแแแแก แ แแแแ แช แคแแแ แกแแกแขแแแแก แแแแแ แฉแแแแแกแ แแ แแแแฎแแแ แแแแแก แแแแก แจแแ แแก. แแแกแ แแแฅแแแแแแแก แแ แแแชแแแ แแฆแฌแแ แแแแ แจแแแแแแ แแแแ-แกแฅแแแแ:
- แจแแแแฎแกแแแแแ, แ แแ แแแแแแแ แแ แแก แจแแขแงแแแแแแแ แแแแก แจแแกแแฎแแ, แ แแ แแแ แแแแฃแ แกแแแแขแก แจแแฃแซแแแ แจแแแกแ แฃแแแก แแ แแแแแแแแแแก I/O แแแแ แแชแแ.
- แแแแแแแแก แแแแแฃแจแแแแแแแ แแ แแก แคแฃแแฅแชแแ, แ แแแแแกแแช แแซแแฎแแก I/O แ แแแฅแขแแ แ แแแแแแแแก แแแฆแแแแกแแก, แ แแแแแแช แจแแแแแ แแกแ แฃแแแแก แแ แแแแแแแแแแก I/O แแแแ แแชแแแก.
แแแแจแแแแแแแแแแ แแฆแแแแจแแแก, แ แแ I/O แ แแแฅแขแแ แ, แแแแกแแแฆแแ แแแแ, แแ แแก แแ แแซแแคแแก, แแแแ แแ แแ แแคแแ แ แฃแจแแแก แฎแแแก แแแแชแแคแชแแแก แแแแแงแแแแแแก แแ แแแแ แซแแคแแแ แแแ แแแแจแ 1 แซแแคแแก: 1 แ แแแฅแขแแ แแก แแแแแคแแ แแแแแ, แ แแแแช แแแแแแฃแจแแแแแแ แงแแแแ CPU แแแ แแแ.
ะ ะตะฐะปะธะทะฐัะธั
แฉแแแ แแแแแแแแแกแแแ แกแแฏแแ แ แแแขแแ แคแแแกแก แคแแแแจแ reactor.h
reactor.c
reactor.h
แจแแแแแแ แจแแแแแแ แแแแชแฎแแแแแแแแกแแแแ:
แแแแแแ แแชแแแแแก แฉแแแแแแ แ แแแฅแขแแ แจแ.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;
}
แจแแฏแแแแแแกแแแแก, แแแแฎแแแ แแแแแก แแแแจแ แคแฃแแฅแชแแแแแก แแแแแซแแฎแแแแก แฏแแญแแ แแแแฆแแแก แจแแแแแ แคแแ แแแก:
แแ แแ แฎแ แแฎแแแแแ แกแแ แแแ แ
แแแแกแแแแแก, แ แแ แจแแแแแแฌแแแ I/O แ แแแฅแขแแ แ แแแฆแแแ แแแขแแแ แแแแ, แฉแแแ แแแแฌแแ แ แแแ แขแแ 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
แคแฃแแฅแชแแแก แแ แแขแแขแแแแแแก แฉแแแแแแ แกแแแ แแ.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()
. แแแแ แ แแแแแฎแแขแแแก แแแแจแแแแแแแแก แแแแ แแแก แจแแชแแแแแก แแ แแฃ แแแ แแแ trueแ, แแซแแฎแแแก แคแฃแแฅแชแแแก 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()
, แแแแ แแ แแก แแแแแชแแแแแแก แแแกแแแแแแแแ. แแก แคแฃแแฅแชแแ แแแแแแขแก แฃแแแแแแแก HTTP แแแกแฃแฎแก, แ แแแแแแช แจแแแชแแแก HTML แแแแแกแแฎแฃแแแแแก แแ แจแแแแแ แชแแแแก แแแแแแแแก แแแแแฃแจแแแแแแแก. 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
แแ แแแฅแขแแก root-แจแ) แแ แแแฃแจแแแ แแแแแแแฌแแ แ แกแแ แแแ แ, แแแฎแกแแแแ
แจแแกแ แฃแแแแแก แแแแแแแ
แแฉแแแแ แฉแแแ แแแแฅแแแแก แกแแแชแแคแแแแชแแแแ
$ 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
-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 แฌแฃแแจแ แแแแฃแจแแแแแฃแแ แแแแฎแแแแแแแก แ แแแแแแแแแก แแแแแแแแแแฃแแแแแก แแแแจแแ แแแแก แ แแแแแแแแแแ:
แฉแแแ แแฎแแแแแ, แ แแ แ แแแแแแแแ แแกแแฃแแ แแแแจแแ แแก แจแแแแแ, แแ แแแ แกแแ แแแ แแ แแแแฃแจแแแแแฃแแ แแแแฎแแแแแก แ แแแแแแแแ แแแแแแ แแ แแแแแแก (แแ แแแแแแแแแแฃแ แแแ แกแแแจแ แแก แฃแคแ แ แจแแกแแแฉแแแแแ). แแก แแแแแแจแแ แแแฃแแแ Linux TCP/IP แกแขแแแแก แแแแฎแแ แชแแแแแแแกแแแ? แแแแแ แแแแแแ แแแฌแแ แแ แแฅแแแแ แแแ แแฃแแแแ แแ แแคแแก แแ แฅแชแแแแก แจแแกแแฎแแ แแ แแแขแแแแแแชแแแแแก แจแแกแแฎแแ แแแแแแขแแ แแแจแ.
แ แแแแ แช
I/O แ แแแฅแขแแ แแก แแแแแแแแแแแแแ
แแฅแแแ แฃแแแ แแแกแแแแแ, แ แแ I/O แ แแแฅแขแแ แ แแ แแ แแก แแแแแแแแแแแแแแก แแแ แแจแ, แแแ แซแแ:
- I/O แ แแแฅแขแแ แแก แแแแแงแแแแแ แแ แแแแแซแแคแแแ แแแ แแแแจแ แแแ แแแแฃแแฌแแแแ แฃแคแ แ แ แแฃแแแ, แ แแแแแ แแฅแแแ แแแแแฌแแแ แแแแแแแแแก แฎแแแแ แแแ แแแ.
- แแ แแฅแขแแแ แแแแฉแแแแแแก, แ แแ แฃแแแขแแก แจแแแแฎแแแแแจแ แแแขแแแ แแแ แแ แแแ แแแแแ แแแแแแ, แ แแแแช แจแแแซแแแแ แแแแแแฌแแแแก แแ แแ แซแแคแแก แญแ แ, แฎแแแ แแแแ แ แแแแแแแแฃแแแ แกแแแฃแจแแแแ.
- แแฃ แแ แแ แแแแแแแแก แแแแแฃแจแแแแแแแ แแแแแแแแแก แแแแแก, แแแแแ แกแแกแขแแแแก แแแแแ แฉแแแแแแช แแแแแแแแแก, แ แแแแช แจแแแซแแแแ แแแแแแฌแแแแก แซแแแแแ แกแแแแแแแแ แจแแชแแแแแแ.
แฌแงแแแขแก แแ แแ แแแแแแแแก
แแแกแแแแ
แกแฌแแ แแ แแฅ แแแกแ แฃแแแ แฉแแแแ แแแแแแฃแ แแแ แแแแ แแแแแ แแแ แแแแแ แแ แแคแแแแ แแก แแแแแแแแแแฅแแจแ.
แแฅแแแ แแ แฃแแแ แจแแฉแแ แแแ แแแแแ, แ แแแแแ แแ แกแแแแแก แแ แแแแแ แกแฎแแ, แแแแแแ แแ แกแแแแขแแ แแกแ แแแแแแแ แฅแกแแแฃแ แ แแ แแแ แแแฃแแ แฃแแ แฃแแแแแงแแคแแก แแแฌแแ แแกแแแแก แกแฎแแแแแกแฎแแ แแแแแก แแแฎแแ แฎแแแฃแแแแแแ แแ แกแแฉแฅแแ แแ. แกแแแแขแแ แแกแแ, แฉแแแ แแแ แแ, แฅแแแแแ แแแชแแแฃแแแ แแแฃแแแแ.
แจแแแแแ แฏแแ แแ!
แกแแแแขแแ แแกแ แแ แแแฅแขแแแ
- แแแแ
Rust
แแแแแ แ แ แฌแแแแแแแฎแ?
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/
แฌแงแแ แ: www.habr.com