- BrilliantServer
- λͺ©μ°¨
- 0 Introduction
- 1 socket ν΅μ
- 2 TCP Connection
- 3 I/O λ€μ€ μ²λ¦¬
- 4 HTTP
- 5 Common Gateway Interface
- 6 βμλ²λ μ£½μ§ μμ!β
- 7 References
- BrilliantServer λ RFC 9110, 9112 μ μ μλ κ·κ²©μ λ°λ₯΄λ HTTP/1.1 λ²μ origin server μ ꡬνμ λλ€.
- μ΄ νλ‘μ νΈλ Google C++ Style Guide λ₯Ό λ°λΌ C++98 λ‘ μμ±λμμ΅λλ€.
kqueue
λ₯Ό νμ©ν event loop κΈ°λ° non-blocking I/O multiplexing- RFC 3875 λ₯Ό λ°λ₯΄λ CGI μ§μ
- static νμΌμ λν
GET
/POST
/DELETE
HTTP Request μ²λ¦¬POST
λ©μλλ‘ νμΌ μ λ‘λ
- HTTP κ·κ²©μ λ§λ HTTP μλ΅ μμ±
- name-based virtual hosting μ§μ
- directory listing μ§μ
git clone https://github.com/brilliantshell/webserv.git && \
cd webserv && \
make -j
./BrilliantShell [path/to/config]
config νμΌ μμ± κ·μΉμ λ€μκ³Ό κ°μ΅λλ€. Configuration νμΌ κ·μΉ
-
socket ν΅μ μ IPC (Inter Process Communication) μ ν μ’ λ₯λ€.
-
socket νμΌμ socket ν΅μ μ μ’ μ μΌλ‘ (endpoint) socket νμΌμ μ° νλ‘κ·Έλ¨μ socket νμΌμ μ° λ€λ₯Έ νλ‘κ·Έλ¨κ³Ό connection μ μ립νκ±°λ, μλ‘μ μ£Όμλ‘ datagram μ μ μ‘νμ¬ μλ‘ ν΅μ ν μ μλ€.
-
socket
ν¨μλ‘ socket νμΌμ μ΄ μ μμΌλ©°, μ±κ³΅ μ ν λΉ λ fd κ° λ°νλλ€.#include <sys/socket.h> int socket(int domain, int type, int protocol);
domain
λ‘ μ΄λ€ λλ©μΈμμ ν΅μ ν μ§ μ ν μ μλ€. μ¬λ¬κ°κ° μμ§λ§ (OS X μλ 8κ°, Linux μλ λ λ§λ€) μ€μν λκ°λPF_LOCAL
κ³ΌPF_INET
μ΄λ€.PF_LOCAL
- λλ©μΈ/UNIX socket μ΄λΌκ³ λΆλ₯΄λ λ‘컬 νλ‘μΈμ€ κ° ν΅μ μ μν λλ©μΈPF_INET
- TCP socket μ΄λΌκ³ λΆλ₯΄λ IP ν΅μ μ μν λλ©μΈ
type
λ‘ μ μ‘νλ λ°μ΄ν°μ λ¨μλ₯Ό μ ν μ μλ€.- SOCK_STREAM - connection μ립 & byte stream μΌλ‘ ν΅μ
- SOCK_DGRAM - μλμ μ£Όμλ‘ datagram μΌλ‘ ν΅μ
- SOCK_RAW - datagram μΌλ‘ ν΅μ , λ΄λΆ λ€νΈμν¬ μΈν°νμ΄μ€μ μ κ·Ό κ°λ₯
protocol
μλ μμΌμ΄ λ°λ₯Ό νλ‘ν μ½μ μ§μ νλ€. κ°μ νλ‘ν μ½λ‘ μ΄λ¦° μμΌλ€λΌλ¦¬λ§ ν΅μ μ΄ κ°λ₯νλ€. TCP λ 6. (/etc/protocols
μ°Έκ³ )
π‘ μ΄ λ¬Έμλ Web Server μ κ΄λ ¨λ λ¬Έμμ΄κΈ° λλ¬Έμ μλμμλ TCP socket μ λν΄μλ§ μ€λͺ νλ€.
-
socket μμ± ν
bind
ν¨μλ‘ ν΄λΉ μμΌμ μ£Όμ/μλ³μλ₯Ό λΆμ¬ν μ μλ€.#include <sys/socket.h> int bind(int socket, const struct sockaddr *address, socklen_t address_len);
socket
μ ν΄λΉ socket μ fd μ΄λ€.address
λ ν λΉν μ£Όμ μ 보λ₯Ό λ΄λ ꡬ쑰체μ μ£Όμκ°μ΄λ€. UNIX socket μ κ²½μ°struct sockaddr_un
μ μ£Όμκ°μ, TCP socket μ κ²½μ°struct sockaddr_in
(IPv4) /struct sockaddr_in6
(IPv6) μ μ£Όμκ°μ μΊμ€ν ν΄μ λ£μ΄μ€λ€.address_len
μλaddress
ꡬ쑰체μ κΈΈμ΄λ₯Ό λ£μ΄μ€λ€.
-
IPv4 μ κ²½μ° μ£Όμ ꡬ쑰체λ μλμ κ°λ€.
struct in_addr { in_addr_t s_addr; }; struct sockaddr_in { __uint8_t sin_len; sa_family_t sin_family; // AF_INET in_port_t sin_port; // port number struct in_addr sin_addr; // listen ν IP μ£Όμ sin_addr.s_addr μ μ€μ char sin_zero[8]; };
sin_addr.s_addr
λ Server μ κ²½μ°INADDR_ANY
(0) λ‘ μ€μ νμ¬ μ΄λ€ μ£Όμλ μ§sin_port
μ μ€μ ν port λ‘ μ°κ²°μ μλνλ©΄ listen νκ² μ€μ νλ€.- port μ address λ network byte order λ‘ μ μ₯λΌμΌνκΈ° λλ¬Έμ
<arpa/inet.h>
ν¨μλ€μ νμ©ν΄μΌνλ€.
-
HTTP Server λ socket νμΌμ μ΄μ΄ (
PF_INET
,SOCK_STREAM
, 6) Client νλ‘κ·Έλ¨λ€κ³Ό TCP connection μ μ립νμ¬ ν΅μ νλ€. (HTTP/3.0 λΆν°λ UDP μ¬μ©) -
Server μ μ°κ²°μ μλνλ Client μ socket μ βactiveβ socket, Client μ μ°κ²° μλλ₯Ό κΈ°λ€λ¦¬λ Server μ socket μ βpassiveβ socket μ΄λΌκ³ λΆλ₯Έλ€.
-
socket κ°μ TCP connection μ΄ μ립λλ κ³Όμ μ μμ°¨μ μΌλ‘ μ€λͺ νλ©΄ μλμ κ°λ€.
-
bind
μ΄ν Server μ μμΌμlisten
ν¨μλ₯Ό νΈμΆνμ¬ βpassiveβ/βlisteningβ μνλ‘ μ ννλ€.#include <sys/socket.h> int listen(int socket, int backlog);
socket
μ ν΄λΉ socket μ fd μ΄λ€.backlog
λ μ°κ²° μ립μ κΈ°λ€λ¦¬λ μμ²λ€μ queue μ μ΅λ κΈΈμ΄μ΄λ€. queue κ° κ½ μ°¨μλ μνμμ μ°κ²° μ립 μμ²μ΄ μ€λ©΄ Client λ ECONNREFUSED μλ¬λ₯Ό λ°ν λ°λλ€. (silent limit 128)
-
Server λ βlisteningβ socket μ΄ μ€λΉλ ν
accept
ν¨μλ‘ block νλ©° Client μ μ°κ²° μ립 μμ²μ κΈ°λ€λ¦°λ€.#include <sys/socket.h> int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
socket
μ βpassiveβ socket μ fd μ΄λ€.address
λ Client μ βactiveβ socket μ μ£Όμ μ 보λ₯Ό λ΄μ ꡬ쑰체μ μ£Όμλ€.address_len
μλaddress
ꡬ쑰체μ κΈΈμ΄λ₯Ό λ£μ΄μ€λ€.
-
Client μμΌμ
connect
ν¨μλ₯Ό νΈμΆνμ¬ Server μ TCP μ°κ²° μ립μ μμ²νλ βactiveβ μν μ μννλ€.#include <sys/types.h> #include <sys/socket.h> int connect(int socket, const struct sockaddr *address, socklen_t address_len);
socket
μ ν΄λΉ socket μ fd μ΄λ€.address
μλ μ°κ²°νκ³ μ νλ Server μ μμΌμ ν λΉλ μ£Όμκ° μ λ ₯λ ꡬ쑰체μ μ£Όμκ°μ λ£μ΄μ€λ€.address_len
μλaddress
ꡬ쑰체μ κΈΈμ΄λ₯Ό λ£μ΄μ€λ€.
-
Client μ μ°κ²° μ립 μμ²μ μμ νλ©΄
accept
λ blocking μ νκ³ Client μ βactiveβ socket κ³Ό μ°κ²°μ΄ μ립ν μλ‘μ΄AF_INET
socket μ μμ±νκ³ , μ°κ²°μ΄ μ립λλ©΄ (TCP ESTABLISHED) κ·Έ socket μ fd λ₯Ό λ°ννλ€.
-
-
Server λ
accept
ν¨μκ° λ°νν fd μ read/recv νμ¬ Client κ° λ³΄λΈ μμ²μ μ½κ³ , write/send νμ¬ Client μκ² μλ΅μ λ³΄λΌ μ μλ€.> π‘ socket μ read/write ν λ, νλ²μ νΈμΆλ‘ μμ€ν μ TCP window size λ₯Ό λμ μ μλ€.
sysctl -a | grep buf
λ‘ max limit μ νμΈν μ μλ€. (auto * bufmax κ° window size)![tcp max buffer](/assets/tcp-max-buffer.png)
-
socket μ€μ μ
getsockopt
λ‘ νμΈ,setsockopt
λ‘ λ³κ²½ν μ μλ€.#include <sys/socket.h> int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len); int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
-
setsockopt
μoption_name
μΈμλ‘send
/recv
buffer size (SO_SNDBUF
/SO_RCVBUF
) λ± μ¬λ¬κ°μ§ μμ±μ λ³κ²½ν μ μλ€.
-
νΉμ ip + port λ‘
bind
λμ΄μλ passive socket μ΄ Server μ’ λ£ μ νΉμ μ€ν μ€ μ΄λ€ μ΄μ λ‘ λ«νμ λ ν΄λΉ socket μTIME-WAIT
μνκ° λκ³ νΉλ³ν μ€μ μ΄ μμλ€λ©΄ 2MSL λμ ν΄λΉ ip + port λ‘μbind
κ° λΆκ°λ₯ν΄μ§λ€. -
Server κ° μ¬μ€ννκΈ° μν΄ μ’ λ£ ν 2MSL μ κΈ°λ€λ €μΌνλ κ²μ λ무 λΆνΈνκΈ° λλ¬Έμ, μ΄λ₯Ό ν΄κ²°νκΈ° μν΄ BrilliantServer μ passive socket λ€μ
SO_REUSEADDR
λ‘ μ€μ λμλ€. νΉμ ip + port λ‘bind
νκΈ° μ μSO_REUSEADDR
μ€μ μ νλ©΄, Server λ 2MSL μ κΈ°λ€λ¦¬μ§ μκ³ λ°λ‘ ν΄λΉ ip + port λ₯Ό μ¬μ¬μ© (λ€μbind
) ν μ μλ€.TIME-WAIT
socket λ€μ΄ λ¨μ§λ§ μ΄λ μ μμ μΈ μ’ λ£ μ μ°¨μ΄κ³ , Server μκ² λ¬Έμ κ° λμ§ μλλ€.// opt μλ 0 μ΄ μλ μ«μκ° λ€μ΄κ°λ©΄ λλ€ (bool κ°μ μν ) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { PRINT_ERROR("address cannot be reused : " << strerror(errno)); close(fd); return -1; } errno = 0; if (bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { PRINT_ERROR("socket for " << kPort << " cannot be bound : " << strerror(errno)); close(fd); return -1; } listen(fd, BACKLOG);
-
SO_LINGER
μ΅μ μΌλ‘λ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€.SO_LINGER
μ΅μ μstruct linger
μ μ£Όμλ₯Όsetsockopt
μoption_value
λ‘ λ겨주며,l_onoff
κ° 0 μ΄ μλκ³l_linger
κ° μμ μ μλ‘ μ€μ λ κ²½μ°, Server κ° socket μclose
νμ λ μμ§ λ³΄λ΄μ§μ§ μμ λ°μ΄ν°κ° λ¨μ μλ€λ©΄l_linger
μ΄ λ§νΌclose
λ₯Ό block νκ² μ€μ νλλ° μ¬μ©λλ€.l_linger
κ°μ 0 μΌλ‘ μ€μ νλ©΄ μ μμ μΈ TCP μ°κ²° μ’ λ£ μ μ°¨κ° μμλμ§ μκ³ , TCP μ°κ²°μμRST
control bit μ΄ λ³΄λ΄μ§λ©°close
ν socket μ΄TIME-WAIT
μνμ λΉ μ§μ§ μλλ€. νμ§λ§ λΉμ μμ μΌλ‘ TCP μ°κ²°μ λκΈ° λλ¬Έμ μ΄μ TCP μ°κ²°μ΄ μ λλ‘ μ 리λμ§ μμ Connection Reset by Peer μλ¬κ° λ°μν μνμ΄ ν¬λ€.struct linger { int l_onoff; /* option on (0)/off (non-zero) */ int l_linger; /* linger time (sec) */ };
-
TCP connection state diagram
+---------+ ---------\ active OPEN | CLOSED | \ ----------- +---------+<---------\ \ create TCB | ^ \ \ snd SYN passive OPEN | | CLOSE \ \ ------------ | | ---------- \ \ create TCB | | delete TCB \ \ V | \ \ rcv RST (note 1) +---------+ CLOSE | \ -------------------->| LISTEN | ---------- | | / +---------+ delete TCB | | / rcv SYN | | SEND | | / ----------- | | ------- | V +--------+ snd SYN,ACK / \ snd SYN +--------+ | |<----------------- ------------------>| | | SYN | rcv SYN | SYN | | RCVD |<-----------------------------------------------| SENT | | | snd SYN,ACK | | | |------------------ -------------------| | +--------+ rcv ACK of SYN \ / rcv SYN,ACK +--------+ | -------------- | | ----------- | x | | snd ACK | V V | CLOSE +---------+ | ------- | ESTAB | | snd FIN +---------+ | CLOSE | | rcv FIN V ------- | | ------- +---------+ snd FIN / \ snd ACK +---------+ | FIN |<---------------- ------------------>| CLOSE | | WAIT-1 |------------------ | WAIT | +---------+ rcv FIN \ +---------+ | rcv ACK of FIN ------- | CLOSE | | -------------- snd ACK | ------- | V x V snd FIN V +---------+ +---------+ +---------+ |FINWAIT-2| | CLOSING | | LAST-ACK| +---------+ +---------+ +---------+ | rcv ACK of FIN | rcv ACK of FIN | | rcv FIN -------------- | Timeout=2MSL -------------- | | ------- x V ------------ x V \ snd ACK +---------+delete TCB +---------+ -------------------->|TIME-WAIT|------------------->| CLOSED | +---------+ +---------+
-
TCP Header Format
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window | | | |R|E|G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | [Options] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | : : Data : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Note that one tick mark represents one bit position.
- Seqeunce Number : 32 bits
- ν΄λΉ μΈκ·Έλ¨ΌνΈμ 첫 λ°μ΄ν° octet μ sequence λ²νΈ. μμΈλ‘ SYN 컨νΈλ‘€ λΉνΈκ° μΈν λ λλ sequence λ²νΈλ ISN, 첫 λ°μ΄ν° octet μ ISN + 1 λ‘ μ€μ λλ€.
- Acknowledgement Number : 32 bits
- ACK 컨νΈλ‘€ λΉνΈκ° μΈν λλ©΄, λ€μμ λ°μ κ²μΌλ‘ μμλλ μΈκ·Έλ¨ΌνΈμ μνμ€ λ²νΈκ° μ€μ λλ€. ν λ² μ°κ²°μ΄ μ립λλ©΄ νμ μ μ‘λλ€.
- Reserved (Rsrvd) : 4 bits
- 컨νΈλ‘€ λΉνΈλ₯Ό νμνλ€.
- Window : 16 bits
- λ°μ μκ° λ°μ μ μλ TCP Window ν¬κΈ° (unsigned number)
- Seqeunce Number : 32 bits
-
three-way-handshake
TCP Peer A TCP Peer B 1. CLOSED LISTEN 2. SYN-SENT --> <SEQ=100><CTL=SYN> --> SYN-RECEIVED 3. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED 4. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED 5. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED
- μ 컀λ₯μ
μ λ§λ€κΈ° μν΄μλ κ° Peer λ³λ‘ 32bit ν¬κΈ°μ
ISN
(Initial Sequence Number) μ μμ±νκ³ μλ³μλ‘μ¨ μ¬μ©νλ€.ISN
μ μ¬μ©νλ©΄ ν¬νΈλ₯Ό μ¬μ¬μ© ν κ²½μ° κ° μ»€λ₯μ μ ꡬλΆνμ¬ λ°μ΄ν°κ° νΌμ¬λμ§ μκ³ SEQ λ₯Ό μΆμΈ‘νκΈ° μ΄λ €μμ§λ―λ‘ λ³΄μμ΄ κ°νλλ€. - λ°μ΄ν°λ₯Ό μ£Όκ³ λ°μ μ μλ μνκ° λλ €λ©΄ λ peer λͺ¨λ
ESTABLISHED
μνκ° λμ΄μΌ νλ€
- μλ² (μ κ·Έλ¦Όμμ Peer B) μΈ‘μμ passive open μΌλ‘
LISTEN
μνκ° λλ©΄ ν΄λΌμ΄μΈνΈ (Peer A) κ° active open μ μλνκΈΈ κΈ°λ€λ¦°λ€. - ν΄λΌμ΄μΈνΈκ° passive open νλ©΄ μμ μ ISN μ μνμ€ λλ² (SEQ) λ‘ SYN 컨νΈλ‘€ λΉνΈμ ν¨κ» μλ²μκ² λ³΄λ΄κ³
SYN_SENT
λ‘ μ ννλ€. SYN μ λ°μμΌλ―λ‘ μλ²λSYN_RECEIVED
μνλ‘ μ ννλ€. - μΈκ·Έλ¨ΌνΈλ₯Ό λ°μΌλ©΄ μλ²λ μμ μ
ISN
μ μνμ€ λλ²(SEQ) λ‘, λ°μλ μΈκ·Έλ¨ΌνΈμ SEQ + 1 κ°μ ACK μΌλ‘ μ€μ νμ¬ λ³΄λΈλ€. 컨νΈλ‘€ λΉνΈ SYN, ACK λ‘ νμΈ μλ΅μ λ°μ ν΄λΌμ΄μΈνΈκ°ESTABLISHED
λ‘ μ ννλ€. - ν΄λΌμ΄μΈνΈκ° ACK λ₯Ό 보λ΄κ³ μλ΅ λ°μ μλ²λ
ESTABLISHED
λ‘ μ ννλ€. - λ λͺ¨λ
ESTABLISHED
μΈ μνμμ data λ₯Ό μ£Όκ³ λ°μ μ μλ€. 1.2 TCP μ°κ²° μ립 & Passive vs. Active
- μ 컀λ₯μ
μ λ§λ€κΈ° μν΄μλ κ° Peer λ³λ‘ 32bit ν¬κΈ°μ
- TCP Window λ κ° peer κ° μμλ‘ λ°μ΄ν°λ₯Ό λ°μ μ μλ λ²νΌμ΄λ€. μμ© νλ‘κ·Έλ¨ μΈ‘μμ λ²νΌλ₯Ό μ½μ΄κ°λ©΄ clear νλ€. μΈκ·Έλ¨ΌνΈμ Window ν€λ νλλ‘ λ¨μ Window size λ₯Ό μλνΈ peer μκ² μλ €μ€ μ μλ€. λ¨μ TCP Window μ¬μ΄μ¦κ° 0μ κ°κΉμ μ§λ©΄ λ²νΌκ° λΉμμ‘λ€λ μ λ°μ΄νΈκ° κ° λ κΉμ§ μ μ‘μ΄ μ€λ¨λλ€.
- socket read κ° μ§μ°λλ©΄ Window size κ° μμμ Έ μλνΈ peer μ μ μ‘μ΄ μ€λ¨λλ€.
- four-way-handshaking
TCP Peer A TCP Peer B
1. ESTABLISHED ESTABLISHED
2. (Close)
FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> --> CLOSE-WAIT
3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT
4. (Close)
TIME-WAIT <-- <SEQ=300><ACK=101><CTL=FIN,ACK> <-- LAST-ACK
5. TIME-WAIT --> <SEQ=101><ACK=301><CTL=ACK> --> CLOSED
6. (2 MSL)
CLOSED
- TIME_WAIT & CLOSE_WAIT
- μλ² (μ κ·Έλ¦Όμμ Peer A) μΈ‘μμ
close
νκ³ ν΄λΌμ΄μΈνΈ ****(μ κ·Έλ¦Όμμ Peer B) μΈ‘μμ ACK λ₯Ό 보λ΄κΈ° μ νλ‘μΈμ€λ₯Ό μ’ λ£ν΄ λ²λ¦΄ κ²½μ° μλ² μΈ‘μμ λ΅μ₯μ λ°μ§ λͺ»νκΈ° λλ¬ΈμTIME_WAIT
μνμ κ±Έλ¦¬κ² λλ€. νλ‘κ·Έλ¨ μμμTIME-WAIT
μνλ₯Ό μ²λ¦¬νκΈ° μ΄λ ΅κ³ , μ¬ μ°κ²°μ μν΄μλ 2MSL (Maximum Segment Lifetime) λ§νΌ κΈ°λ€λ €μΌ νλ―λ‘ μλ² μΈ‘μclose
λ μ μ€νκ² μ¬μ©ν΄μΌ νλ€. - μ΄μ© μ μλ κ²½μ°
shutdown
μ μ΄μ©ν΄ socket μ write λΆν° λ«λλ€.
- μλ² (μ κ·Έλ¦Όμμ Peer A) μΈ‘μμ
- CLOSE μ μ°¨ μ€ νΉμ μνμμ pending λλ©΄ μ μμ μΈ μ°κ²°μ΄ μ΄λ£¨μ΄μ§μ§ λͺ»νλ λ¬Έμ κ° μκΈΈ μ μλ€.
- CLOSE_WAIT
- passive close νλ κ²½μ°, active close ν μλνΈ peer κ° λ³΄λΈ
FIN
μ λ°κ³close
νκΈ° μ μνμ΄λ€. CLOSE_WAIT
μ μ μμ μΈclose
μμ²μΌλ‘ μ²λ¦¬νλFIN_WAIT
λTIME_WAIT
κ³Όλ λ€λ₯΄κ² μΌμ μκ°μ΄ μ§λλ μ¬λΌμ§μ§ μμΌλ―λ‘ νλ‘μΈμ€μ μ’ λ£λ λ€νΈμν¬ μ¬μμμΌλ‘ ν΄κ²°ν΄μΌ νλ€.- Brilliant Server μμλ kqueue TIMER μ΄λ²€νΈλ₯Ό μ΄μ©νμ¬ μΌμ μκ°μ΄ μ§λλ©΄ λͺ
μμ μΌλ‘
close
μμ²μ 보λ΄λ λ°©λ²μΌλ‘ ν΄κ²°νμλ€.TIMER event μif (events[i].filter == EVFILT_TIMER) { ClearConnectionResources(events[i].ident); }
ident
μ λ°μΈλ© λ μμΌ μfd
λ₯Ό λμΌνκ² μ€μ νμ¬ClearConnectionResources
μμclose
λ₯Ό νΈμΆνκ³ μμμ 리νλ€.
- passive close νλ κ²½μ°, active close ν μλνΈ peer κ° λ³΄λΈ
- TIME_WAIT
- active close ν μλνΈμ
FIN
μ κΈ°λ€λ¦¬λ μνμ΄λ€. 2MSL μ΄ μ§λ νμCLOSED
μνκ° λμ΄μΌ λ€μ ν΄λΉ ν¬νΈμ λ°μΈλ© ν μ μλ€. TIME_WAIT
μ΄ μκ³ λ°λ‘ μ°κ²°μ΄ λ«νλ κ²½μ° λ¬Έμ λλ μν©close
λλ μμΌμ send λ²νΌμ μμ§ λ³΄λ΄μ§ μμ λ°μ΄ν°κ° λ¨μμμ μ μλ€.- μλνΈ peer μμ 보λ΄κ³ μμ§ λλ¬νμ§ λͺ»ν λ°μ΄ν°κ° μμ μ μλ€. μλνΈμ μμ§ ACK μ λ°μ§ λͺ»νκΈ° λλ¬Έμ κ³μ μ¬μ μ‘μ μλνκ±°λ λ°μ΄ν° μμ€μ΄ μΌμ΄λλ€.
- μλνΈ peer κ°
LAST_ACK
μνμμ 보λΈFIN
μ λ°μ μ μμΌλ―λ‘ μλ΅λ μ€ μ μλ€. μλνΈμ μμ§ACK
μ λ°μ§ λͺ»νκΈ° λλ¬Έμ κ³μ μ¬μ μ‘μ μλνκ±°λ λ°μ΄ν° μμ€μ΄ μΌμ΄λλ€.
TIME_WAIT
μ΄ λ¨μμμ΄λ μbind
λ₯Ό νκ³ μΆμ κ²½μ°setsockopt
λ₯Ό μ΄μ©ν μ μλ€.SO_LINGER
λ₯Ό μ¬μ©ν λ°©λ²- μΌλ°μ μΈ κ²½μ°
close
μ΄νμ μ κ²½μ°λ€μ΄ λͺ¨λ μ²λ¦¬λμ§λ§l_linger
λ₯Ό λ§€μ° μκ² μ€μ νμ¬SO_LINGER
λ₯Ό μ¬μ©νλ©΄ λ°μ΄ν° μμ€ λΏλ§ μλλΌRST
컨νΈλ‘€ λΉνΈλ₯Ό μ΄μ©νμ¬ μμΌμ μ’ λ£νλ―λ‘ μλνΈμμConnection reset by peer
μ€λ₯λ₯Ό λ°μμν¬ μ μλ€.
- μΌλ°μ μΈ κ²½μ°
SO_REUSEADDR
μ μ¬μ©ν λ°©λ²TIME_WAIT
μνμμλ μλ‘μ΄ socket μ κ°μ μ£Όμμbind
ν μ μκ² νλ€.
- Brilliant Server μμμ ν΄κ²°λ² 1.4.0 SO_REUSEADDR vs SO_LINGER
- active close ν μλνΈμ
-
I/O Multiplexing μ νλμ
event loop
μμ μ¬λ¬κ°μI/O events
λ₯Ό μ²λ¦¬νλ λ°©μμ΄λ€. -
κ° I/O λ
non-block
μΌλ‘ μ΄λ£¨μ΄μ§λ©° I/O μμ μ΄ μΌμ΄λλFD
λ€μ κ°μνλ μμ€ν μ½(select
,poll
,epoll
,kqueue
β¦ ) μ νμ©νμ¬FD
μevent
μ λ°μ μ¬λΆλ₯Ό κ°μνκ³ , λ§μ½ μ΄λ²€νΈκ° μλ€λ©΄ μ μ ν μμ μ ν΄μΌνλ€. -
kqueue
λ₯Ό μλ‘ λ€λ©΄,non-block I/O
λ₯Ό νΈμΆ ν λ€kevent
λ‘block
μ μν€κ³ ,FD
μ λ°μνevent
κ° μλμ§ νμΈνλ€.kevent
λ νλμFD
λΏλ§ μλλΌ, μ¬λ¬κ°μFD
μ λνevent
λ₯Ό κ°μ§ν μ μμ΄μ μ¬λ¬μ I/O λ₯Ό ν νλ‘μΈμ€μμ κ΄λ¦¬ν μ μκ² λλ€.
- κΈ°μ‘΄
read/write
νΈμΆμ νλ‘μΈμ€λ₯Όblock
μν€κ³ I/O μμ μ΄ μλ£λκΈ°λ₯Ό κΈ°λ€λ¦¬μ§λ§,non-block
I/O λread/write
νΈμΆμread/write
κ° κ°λ₯νλ€λ©΄ μμ μ΄ μνλκ³ , κ·Έλ μ§ μλ€λ©΄-1
μ λ°ννλ©°errno
κ°EAGAIN|EWOULDBLOCK
λ‘ μ€μ λλ€.
μΆμ² : https://ecsimsw.tistory.com/entry/Web-server-with-socket-API
-
kqueue
μkevent
λ kernel event notification mechanism μ΄λ©° κ°κ° kernel queue, kernel event λ₯Ό λ»νλ€.#include <sys/types.h> #include <sys/event.h> #include <sys/time.h> int kqueue(void); int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); struct kevent { uintptr_t ident; /* identifier for this event */ int16_t filter; /* filter for event */ uint16_t flags; /* general flags */ uint32_t fflags; /* filter-specific flags */ intptr_t data; /* filter-specific data */ void *udata; /* opaque user data identifier */ }; EV_SET(&kev, ident, filter, flags, fflags, data, udata);
-
kqueue()
μμ€ν μ½μ μλ‘μ΄kqueue
FD
λ₯Ό λ°ννλ€. μ΄FD
λ filters λΌκ³ νλ kernel code μ κ²°κ³Όλ₯Ό κΈ°λ°μΌλ‘ kernel event κ° λ°μνκ±°λ 쑰건μ μΆ©μ‘±νλ©΄, μ¬μ©μμκ² μλ €μ£Όλ μΌλ°μ μΈ λ°©λ²μ μ 곡νλ€. -
kevent
ꡬ쑰체λ (ident
,filter
,udata(optional)
) ννλ‘ μλ³λλ©°kevent
ꡬ쑰체μ ν΄λΉ ννμ λν΄ μλ¦Όμ λ°μ 쑰건μ μ§μ νλ€. I/O eventμ κ²½μ°ident
λ‘ FD κ° λ€μ΄κ°κ³ ,filter
μEVFILT_READ, EVFILT_WRITE
κ°μ λ£μ΄μread/write
μ΄λ²€νΈλ₯Ό λ±λ‘ ν μ μλ€.void HttpServer::InitKqueue(void) { kq_ = kqueue(); // kqueue μμ± if (kq_ == -1) { PRINT_ERROR("HttpServer : kqueue failed : " << strerror(errno)); exit(EXIT_FAILURE); } // kevent ꡬ쑰체 λμ ν λΉ struct kevent* sock_ev = new (std::nothrow) struct kevent[passive_sockets_.size()]; if (sock_ev == NULL) { PRINT_ERROR("HttpServer : failed to allocate memory"); exit(EXIT_FAILURE); } int i = 0; for (ListenerMap::const_iterator it = passive_sockets_.begin(); it != passive_sockets_.end(); ++it) { // kevent ꡬ쑰체 λ°°μ΄ μ΄κΈ°ν (ident: fd) EV_SET(&sock_ev[i++], it->first, EVFILT_READ, EV_ADD, 0, 0, NULL); } // keventμ changlist, nchangesλ₯Ό μΈμλ‘ λ겨 μ΄λ²€νΈ λ±λ‘ if (kevent(kq_, sock_ev, passive_sockets_.size(), NULL, 0, NULL) == -1) { PRINT_ERROR("HttpServer : failed to listen : " << strerror(errno)); exit(EXIT_FAILURE); } delete[] sock_ev; }
-
kevent()
ν¨μλchangelist
μ κ°μνkevent ꡬ쑰체
μ ν¬μΈν°λ₯Ό λ°μ μ΄λ²€νΈλ₯Ό λ±λ‘νλ€.while (true) { // μ΄λ²€νΈκ° λ°μν λ κΉμ§ block int number_of_events = kevent(kq_, NULL, 0, events, MAX_EVENTS, NULL); if (number_of_events == -1) { PRINT_ERROR("HttpServer : kevent failed : " << strerror(errno)); } for (int i = 0; i < number_of_events; ++i) { if (events[i].filter == EVFILT_READ) { /* READ μ΄λ²€νΈ λ°μ, read μμ μννκΈ° */ } else if (events[i].filter == EVFILT_WRITE) { /* Write μ΄λ²€νΈ λ°μ, write μμ μννκΈ° */ } } }
-
eventlist
μλ μ΄λ²€νΈ λ°μμ μ΄λ²€νΈ λ°μ΄ν°λ₯Ό λ°μμ¬kevent ꡬ쑰체
μ ν¬μΈν°λ₯Ό λ°κ³ , μ΄λ²€νΈ λ°μμ λ°μν μ΄λ²€νΈμ κ°μκ° λ°νλκ³ ,eventlist
μ λ£μkevent ꡬ쑰체
μ λ°μ΄ν°κ° λ΄κ²¨μ¨λ€. -
I/O μ κ²½μ° kevent ꡬ쑰체μ ident λ₯Ό FD λ‘ λκΈ°κ³ , filter μ EVFILT_READ|WRITE λ₯Ό μ£Όλ©΄ λ€μκ³Ό κ°μ κ²½μ°μ μ΄λ²€νΈκ° λ°μνλ€.
- READ μ κ²½μ° FD μ μ½μ μ μλ λ°μ΄ν°κ° μμ λ
- WRITE μ κ²½μ° FD μ λ°μ΄ν°λ₯Ό μΈ μ μμ λ
-
μ΄λ²€νΈκ° λ°μν κ²½μ° μ μ ν READ / WRITE νΈμΆμ ν΄μ£Όλ©΄, non-block I/O μμλ μ μ νκ² I/O λ₯Ό μ²λ¦¬ ν μ μλ€.
kqueue
vs select
vs poll
-
select
μλ λ°©μ#include <sys/select.h> int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout);
-
select()
λ μΈμλ‘ κ°μνfd
μ κ°μ(nfds
)λ₯Ό λ°λλ€. -
select()
νΈμΆ μ (0 ~nfds-1
)κ°μ λ°°μ΄μ μννλ©° μ΄λ²€νΈλ₯Ό νμ§νλ€.$O(nfds)$ - μ΄λ²€νΈ λ°μμ λ°μ΄ν°κ° λ³κ²½λ νμΌμ κ°μκ° λ°νλμ΄, λ°°μ΄μ λ€μ μννλ©° μ΄λ€
fd
μμ μ΄λ²€νΈκ° λ°μνλμ§ μ°ΎμμΌ νλ€. -
nfds
κ° 1024 λ₯Ό λμ μ μλ€. -
fd
λ§λ€bitmasking
μ νμ©νμ¬3bit
λ§μΌλ‘ νfd
μ μνλ₯Ό μΆμ ν μ μλ€.
-
-
poll
μλ λ°©μ#include <poll.h> int poll(struct pollfd fds[], nfds_t nfds, int timeout);
-
poll()
μfd
μ μ΄λ²€νΈ μ λ³΄κ° λ΄κΈ΄pollfd
λ°°μ΄κ³Ό, μ€μ λ‘ κ°μνλfd
μ μμΈnfds
λ₯Ό μΈμλ‘ λ°λλ€. -
select()
μμnfds
μ¬μ΄μ¦μ λ°°μ΄μ μννλ©° μ΄λ²€νΈκ° λ°μνfd
λ₯Ό μ°ΎμμΌ νμ§λ§,poll()
μ€μ λ‘ κ°μνλfd
μ κ°μλ§νΌ μνλ₯Ό ν μ μλ€.$O(fd_count)$ - κ°μ κ°λ₯ν
fd
μ μκ° λ¬΄μ νμ΄λ, ν ꡬ쑰체λΉ64bit
μ ν¬κΈ°λ₯Ό κ°μ Έ λ§μ μ΄λ²€νΈλ₯Ό λ€λ£° κ²½μ°select()
λ³΄λ€ μ±λ₯μ΄ λ¨μ΄μ§ μ μλ€.
-
-
select(), poll()
μ λ¬Έμ μ -
select(), poll()
μ νΈμΆ ν λ λ§λ€, μ 체fd
λ°°μ΄μ μΈμλ‘ λκ²¨μΌ νλ©°, μ΄ λ°°μ΄μ΄user-space
μμkernel-space
λ‘ λ³΅μ¬λ λ μλΉν μ€λ²ν€λκ° μ‘΄μ¬νλ€. (95% λ λΆνμν 볡μ¬) -
kernel
μμ μ΄λ²€νΈκ° λ°μνλ©΄,kernel-space
μμλ μ΄λ―Έ μ΄λ²€νΈκ° λ°μνfd
λ₯Ό μλλ°λ λΆκ΅¬νκ³user-space
μμ λ°μν μ΄λ²€νΈλ₯Ό μ°ΎκΈ° μν΄ λ°°μ΄μ μνν΄μΌ νλ€.
-
-
kqueue(), kevent()
μ μ₯μ -
kevent
λkernel
μμ μ€μ λ‘ μ΄λ²€νΈκ° λ°μνfd
list
λ§ λ°ννμ¬,application
μμ μ΄λ²€νΈλ₯Ό λ°λ‘ μΆμ ν μ μλ€. - I/O event λΏλ§ μλλΌ process event, signal event, timer event λ±μ λ±λ‘ ν μ μλ€.
-
-
kqueue(), kevent()
μ λ¨μ - FreeBSD κ³μ΄μ νμ λ μμ€ν μ½ μ΄λΌμ νΈνμ±μ΄ μ’μ§ μλ€. λ컀λ₯Ό νμ©νμ¬ λ¦¬λ μ€μμ μ€ννκ³ μΆμλλ° μ€ν¨νλ€.
-
κΈ°μ‘΄μ
send
λ₯Ό μ΄μ©νμ¬response
λ₯Ό 보λμΌλresponse
μheader
μcontent
κ° λΆλ¦¬λμ΄ μλ μν©μμsend
λ₯Ό μ¬μ©νκΈ° μν΄μcontent
μ λΆνμν 볡μ¬κ° μΌμ΄λλ λ¬Έμ κ° μμλ€.#include <sys/uio.h> ssize_t writev(int fildes, const struct iovec *iov, int iovcnt); struct iovec { char *iov_base; /* Base address. */ size_t iov_len; /* Length. */ };
-
writev
λ₯Ό μ¬μ©νλ©΄,header
μcontent
κ° λ€λ₯Έ λ²νΌμ μλλΌλ,iovec
ꡬ쑰체μheader
μcontent
μ μ£Όμλ₯Ό λ겨주면, νλμ λ²νΌλ‘write
νλ κ²κ³Ό κ°μ ν¨κ³Όκ° μλ€. λ°λΌμ λΆνμν 볡μ¬λ μΌμ΄λμ§ μκ³ ,write
μμ€ν μ½λ μ€μΌ μ μλ€.
- λ€μμ ν΄λΌμ΄μΈνΈκ° μ μν
BUFFER_SIZE
λ³΄λ€ ν° νμΌμ μμ² νμ λ,content
κ°content-length
λ³΄λ€ μ κ² μ μ‘λλ λ¬Έμ κ° μμλ€. μ΄λ₯Όsetsocketopt
ν¨μλ‘socket
μSO_SNDLOWAT
μ΅μ μ μ€μ ν΄κ²°νλ€.setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &buf_size, sizeof(int))
SO_SNDLOWAT
μ΅μ μnon-block socket
μμsocket buffer
μoutput
μ μνbuf_size
λ§νΌμbytes
κ° λΉμ΄μκ±°λ, νλ²μ λͺ¨λ λ°μ΄ν°λ₯Όsocket buffer
μwrite
ν μ μμ λ (λ°μ΄ν°μ ν¬κΈ°κ°buf_size
λ³΄λ€ μμ λ)send()
κ° κ°λ₯ν΄μ§λ©°, κ·Έλ μ§ μμΌλ©΄send()
κ° μ무 λ°μ΄ν°λ μ μ‘νμ§ μκ³ μλ¬κ° λ°μνλ€.kevent
μEVFILT_WRITE
μSO_SNDLOWAT
μ΅μ μ΄ μ μ©λsocket
μ λ±λ‘νκ² λλ©΄, ν΄λΉsocket
μbuf_size
λ§νΌsocket buffer
μwrite
ν μ μμλ μ΄λ²€νΈκ° λ°μνκ² λλ€.buf_size
λ₯ΌSEND_BUFFER_SIZE
μΈ32kb
λ‘ μ μ νμΌλ, μλ²κ° λ무 λ§μ μμ²μ λ°λ μνμμ μ¬μ νcontent
κ° λ μ μ‘λλ λ¬Έμ κ° λ°μνμ¬SEND_BUFFER_SIZE
μ 1.5λ°°λ‘ μ€μ νμ¬ μ΄λμ λ ν΄κ²°νλ€.
- HTTP λ©μμ§λ μλμ μΉμ
λ€λ‘ μ΄λ€μ Έμλ€.
- control data (request line / response line)
- header table
- octet-stream content
- trailer table
- HTTP λ©μμ§μ μμκ³Ό λμ framing μ΄λΌκ³ νκ³ , framing μ μλμ κ°μ νμμΌλ‘ κ²°μ λλ€.
- body κ° μλ κ²½μ°
- (μμ) control data
- header
CRLF
CRLF
(λ)
- body κ° μλ κ²½μ°
- (μμ) control data
- header (
Content-Length: (positive integer)
/Transfer-Encoding: chunked
) CRLF
CRLF
Content-Length
κΈΈμ΄ λ§νΌμ octet-stream bytes content / chunked λ©μμ§κ° λλ λκΉμ§ (λ)
- body length κ²°μ
- 1xx, 204 OR 304 status code λ₯Ό κ°λ μλ΅μ header fields + CRLF + CRLF λ‘ λλλ€.
Transfer-Encoding
&Content-Length
λ λ€ μλ λ©μμ§κ° μμ λλ€λ©΄Transfer-Encoding
μ΄Content-Length
μ κ°μ override νλ€. μ΄λ° λ©μμ§λ request smuggling/ response splitting μ μλμΌ μ μκ³ μλ¬λ‘ μ²λ¦¬λμ΄μΌνλ€.Transfer-Encoding
header field κ° μκ³chunked
κ° λ§μ§λ§ encoding μΌ λ, λ©μμ§ body length λ transfer coding μ΄ λλ¬λ€κ³ μλ €μ€ λκΉμ§ μ½μΌλ©΄μ κ²°μ νλ€. (chunked-size
μ 0 μ΄ μ¬ λκΉμ§ μ½μΌλΌλ λ§μΈ κ² κ°λ€.)- μλ΅ λ©μμ§μ κ²½μ°,
chunked
κ° λ§μ§λ§ encoding μ΄ μλ λ, μλ²κ° μ°κ²°μ λμ λκΉμ§ μ½λλ€. - μμ² λ©μμ§μ κ²½μ°,
chunked
κ° λ§μ§λ§ encoding μ΄ μλ λ, Bad Request (400) & μ°κ²°μ λλλ€.
Transfer-Encoding
μ΄ μκ³ ,Content-Length
κ° μ ν¨νμ§ μμΌλ©΄, λ©μμ§ framing μ΄ μ ν¨νμ§ μλ€ (a κ²½μ° μΈμ). μλ²λ Bad Request (400) & μ°κ²°μ λλλ€.Content-Length: 400,400,400,400
(κ°μ μ«μ & β,β separated list μ΄λ©΄ ν΄λΉ λ°λ³΅λλ μ«μλ‘ μ§μ )
Transfer-Encoding
μ΄ μκ³ ,Content-Length
κ° μ ν¨ν κ²½μ°,Content-Length
μ λͺ μλ μκ° body length.Content-Length
μ λͺ μλ μ λ§νΌμ octets κ° μμ λκΈ° μ λ§μ½ μ‘μ μκ° μ°κ²°μ λκ±°λ μμ μκ° time out λλ©΄ ν΄λΉ λ©μμ§λ λ―Έμμ±μΌλ‘ (incomplete) μΌλ‘ λ³΄κ³ μ°κ²°μ λμ΄μΌνλ€ (MUST).- μμ² λ©μμ§ & μμ μ΄λ€ μΌμ΄μ€μλ ν΄λΉνμ§ μμΌλ©΄ body length λ 0.
- μλ΅ λ©μμ§ & μμ μ΄λ€ μΌμ΄μ€μλ ν΄λΉνμ§ μμΌλ©΄ μλ²κ° μλ΅μ close νκΈ° μ μ λ³΄λΈ λ§νΌμ΄ body length.
- μ°κ²°μ΄ λλμ λ©μμ§κ° λλ 건μ§, λ€νΈμν¬ μλ¬λ‘ μ°κ²°μ΄ λκ²Όλμ§ νλ³νλκ² μ΄λ ΅κΈ° λλ¬Έμ μλ²λ encoding νΉμ length λͺ
μλ₯Ό κΌ ν΄μ€μΌνλ€ (SHOULD).
- close-delimiting μ HTTP/1.0 κ³Όμ νμ νΈνμ±μ μν΄ μ§μνλ€.
- μμ² λ©μμ§λ μ λ close-delimiting μ νμ§ μλλ€. νμ
Content-Length
/Transfer-Encoding
μΌλ‘ body μ λμ μλ €μ€λ€ (MUST).
- μμ² λ©μμ§μ body κ° μλλ°
Content-Length
κ° μλ κ²½μ° μλ²λ Length Required (411) λ‘ μλ΅ν μ μλ€ (MAY). - μμ² λ©μμ§μ
Transfer-Encoding
μ΄ μλλ°chunked
μ΄μΈμ coding μ΄ μ μ©λκ³ , λ©μμ§ κΈΈμ΄λ₯Ό μ μ μλ€λ©΄ ν΄λΌμ΄μΈνΈλchunked
λ₯Ό μ¬μ©νλ κ²λ³΄λ€ μ ν¨νContent-Length
λ₯Ό λͺ μνλ κ±Έ μ°μ ν΄μΌνλ€ (SHOULD). μλ²λ€μ΄chunked
coding μ ν΄μν μ μμ΄λ Length Required (411) λ‘ μλ΅ν μλ μκΈ° λλ¬Έμ΄λ€.
- body κ° μλ κ²½μ°
-
κ°μ IP + port μμμ μ¬λ¬κ°μ Server νΈμ€ν μ΄ κ°λ₯ν΄μ‘λ€. Name-based virtual server λ μμ²μ
Host
ν€λ νλ κ°μΌλ‘ μμ²μ΄ ν₯νλ Server λ₯Ό λΌμ°ν νλ€. -
μλμ κ°μ΄ μλ²κ° μ€μ λμ΄ μμ λ, μμ²μ
Host
ν€λ νλ κ°μ΄ ghan μ΄λ©΄ 첫λ²μ§Έ Server, yongjule λ©΄ μΈλ²μ§Έ Server λ‘ λΌμ°ν λλ€.server { listen 80 server_name ghan ... } server { listen 80 server_name jiskim ... } server { listen 80 server_name yongjule ... }
-
HTTP/1.1 μ
Transfer-Encoding: chunked
ν€λ νλλ‘ content μ 체 κΈΈμ΄λ₯Ό λͺ¨λ₯΄λ content stream μ length-delimited buffer μ μ°μμΌλ‘ μ μ‘ν μ μκ² ν΄μ€λ€.chunked-body = *chunk last-chunk trailer-section CRLF chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF chunk-size = 1*HEXDIG last-chunk = 1*("0") [ chunk-ext ] CRLF chunk-data = 1*OCTET ; a sequence of chunk-size octets
-
μλ μμμ κ°μ΄, 16μ§μλ‘ λͺ μλ
chunk-size
λ€μ μ€μ ν΄λΉ μ¬μ΄μ¦ λ§νΌμ octet stream μ΄ λ°λ₯Έλ€.chunk-size
0 μΌλ‘ transfer coding μ λμ μλ¦¬κ³ ,trailer section
μ΄ μ΄μ΄μ§ μλ μκ³ , CRLF λ‘ body μ λμ νμνλ€.HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked 4\r\n ghan\r\n 6\r\n jiskim\r\n 8\r\n yongjule\r\n 0\r\n \r\n
-
μμ μλ
chunked
transfer coding μ νμ±ν μ μμ΄μΌνλ€ (MUST). -
μμ μλ λ§€μ° ν°
chunk-size
κ° μ¬ μ μλ€λ κ±Έ μμνκ³ , overflow, precision loss μ κ°μ νμ± μλ¬λ₯Ό λ°©μ§ν΄μΌνλ€ (MUST). (HTTP/1.1 μ μ νμ μ€μ νμ§ μμλ€.) -
chunked
μ parameter κ° λΆμΌλ©΄ μλ¬ (SHOULD). -
chunk-ext
κ° μλμ ν¬λ§·μΌλ‘chunk-size
μμ λμ¬ μλ μλ€. μμ μλ μ΄ν΄ν μ μλ (unrecognized) chunk extension μ 무μν΄μΌνλ€ (MUST). (λ€ μ΄ν΄ν μ μκΈ°λ‘ νμβ¦ λ¬Έλ² μ²΄ν¬λ§ νμβ¦)chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token / quoted-string
-
chunked
coding μ μμ λ μμ μλ trailer fields λ₯Ό μ μ§ν μ§ μμ¨μ§ μ ν μ μλ€ (MAY). μ μ§νλ€λ©΄, header field μλ λ€λ₯Έ ꡬ쑰체μ μ μ₯ν΄μΌνλ€.
- Persistence
- HTTP/1.1 μ κΈ°λ³Έμ μΌλ‘ persistent connection μ μ¬μ©νλ©°, νλμ μ°κ²° μμ μ¬λ¬κ°μ μμ²κ³Ό μλ΅μ μ£Όκ³ λ°μ μ μλ€. μ΄λ κ°μ₯ μ΅κ·Όμ λ°μ
protocol version
μ΄λConnection
ν€λ νλμ μν΄ κ²°μ λλλ°, μλμ κ°μ μ°μ μμμ μνμ¬ κ²°μ λλ€.Connection
ν€λ νλμclose
κ° μλ€λ©΄, νμ¬ μλ΅ μ΄νμ connection μ λμ΄μ μ§μλμ§ μλλ€. else;- λ°μ μμ²μ΄
HTTP/1.1
μ΄λ©΄ μ°κ²°μ κ³μ μ§μλλ€. else; - λ°μ μμ²μ΄
HTTP/1.0
μ΄κ³Connection
ν€λ νλκ°keep-alive
λ©΄ μ°κ²°μ κ³μ μ§μλλ€. - νμ¬ μ°κ²° μ΄νμ μ°κ²°μ λ«νλ€.
- HTTP/1.1 μ κΈ°λ³Έμ μΌλ‘ persistent connection μ μ¬μ©νλ©°, νλμ μ°κ²° μμ μ¬λ¬κ°μ μμ²κ³Ό μλ΅μ μ£Όκ³ λ°μ μ μλ€. μ΄λ κ°μ₯ μ΅κ·Όμ λ°μ
- pipelining
persistent connection
μ μ§μνλ ν΄λΌμ΄μΈνΈλ μμ²μpipeline
(μλ΅μ κΈ°λ€λ¦¬μ§ μκ³ μ¬λ¬κ°μ μμ²μ 보λ΄λκ²)μ ν μ μλ€. μλ²λpipeline
μΌλ‘ μ€λ μμ²μ΄ λͺ¨λ μμ νmethod
λ₯Ό κ°μ§ μμ²μ΄λΌλ©΄, μ΄λ₯Ό λ³λ ¬μ μΌλ‘ μ²λ¦¬ν μ μμ§λ§ κ° μμ²μ μμνλ μλ΅μ λ°μ κ²κ³Ό κ°μ μμλ‘ λ³΄λ΄μ€μΌ νλ€.
- Common Gateway Interface (CGI) λ HTTP Server κ° νλ«νΌμ μκ΄ μμ΄ μΈλΆ νλ‘κ·Έλ¨μ μ€νμν¬ μ μκ² ν΄μ£Όλ μΈν°νμ΄μ€λ€.
- RFC 3875 μ κ·κ²©μ΄ μ μλμ΄ μλ€.
- Server λ CGI script λ₯Ό
execve
λ‘ νΈμΆνλ©° μλμ meta-variable λ€μ env λ‘ μ€μ ν΄μ€λ€ (execve
μ μΈλ²μ§Έ μΈμλ‘ μ λ¬)."AUTH_TYPE=" // μλ²κ° μ¬μ©μ μΈμ¦μ μ¬μ©νλ λ°©λ². "CONTENT_LENGTH=" // μμ² λ©μμ§ body μ ν¬κΈ°λ₯Ό μμ§μλ‘ νν "CONTENT_TYPE=" // μμ² λ©μμ§ body μ Internet Media Type "GATEWAY_INTERFACE=CGI/1.1" // server κ° μ μ©νλ CGI version "PATH_INFO=" // Script-URI μ script-path μ μ΄μ΄ λμ€λ λΆλΆ "PATH_TRANSLATED=" // PATH_INFO κΈ°λ°μΌλ‘ ν΄λΉ resource μ local μ λ κ²½λ‘ "QUERY_STRING=" // URL-encoded κ²μ/parameter λ¬Έμμ΄ "REMOTE_ADDR=" // μμ²μ 보λ΄λ client μ λ€νΈμν¬ μ£Όμ "REMOTE_HOST=" // μμ²μ 보λ΄λ client μ λλ©μΈ "REMOTE_IDENT=" "REMOTE_USER=" // μ¬μ©μ μΈμ¦μ μν΄ client κ° μ 곡νλ μ¬μ©μ μλ³μ "REQUEST_METHOD=" // μμ² method "SCRIPT_NAME=" // μμ²μμ cgi script κΉμ§μ κ²½λ‘ "SERVER_NAME=" // μλ² λͺ "SERVER_PORT=" // μλ² ν¬νΈ "SERVER_PROTOCOL=" // μλ² νλ‘ν μ½ "SERVER_SOFTWARE=" // μλ² νλ‘κ·Έλ¨ λͺ
- CGI λ νμ€ μΆλ ₯μ CGI μλ΅μ μμ±νκ³
EOF
λ‘ μλ΅μ λμ Server μκ² μλ¦°λ€. - CGI μ μλ΅μ λ°κΈ° μν΄ Server λ
execve
μ μpipe
λ₯Ό μ΄μ΄ CGI λ‘ λΆν° μλ΅ λ°μ μ±λμ μ€λΉνλ€.
- CGI μλ΅μ header νλμ body λ‘ κ΅¬μ±λλ€.
- header νλλ CGI-field (
Content-Type
|Location
|Status
) + HTTP field (μ ν) + extension field (μ ν) λ‘ μ΄λ£¨μ΄μ§λ€. - body λ
EOF
κΉμ§ μ°μΈ octet-stream μ΄λ€. - CGI μλ΅μ Document Response, Local Redirection Response, Client Redirection Response, Client Redirection Response with Document λ‘ λλλ€.
document-response = Content-Type [ Status ] *other-field NL
response-body
- μΌλ°μ μΈ λ¬Έμ λ°ν,
Content-Type
νλλ νμ,Status
λ μμΌλ©΄ 200 μΌλ‘ κ°μ£Όνλ€.
Location
νλκ° νμμ΄λ€.Location = local-Location | client-Location client-Location = "Location:" fragment-URI NL local-Location = "Location:" local-pathquery NL fragment-URI = absoluteURI [ "#" fragment ] fragment = *uric local-pathquery = abs-path [ "?" query-string ] abs-path = "/" path-segments path-segments = segment *( "/" segment ) segment = *pchar pchar = unreserved | escaped | extra extra = ":" | "@" | "&" | "=" | "+" | "$" | ","
-
Local Redirect
local-redir-response = local-Location NL
- CGI λ
Location
νλ κ°μ 리λ€μ΄λ νΈ ν κ²½λ‘λ₯Ό μ μ΄μ€λ€. - Server λ κ·Έ κ²½λ‘λ‘ μμ²μ΄ μ¨ κ²μ²λΌ μμ²μ μ²λ¦¬νλ€.
- CGI λ
-
Client Redirect
client-redir-response = client-Location *extension-field NL
- CGI λ
Location
νλ κ°μ Client κ° λ¦¬λ€μ΄λ νΈ ν΄μΌν κ²½λ‘λ₯Ό μ μ΄μ€λ€. - Server λ
302 Found
μν μ½λμ ν¨κ»Location
ν€λ νλλ₯Ό Client μκ² μ λ¬νλ©° Client κ° λ¦¬λ€μ΄λ μ μ μνν μ μκ² νλ€.
- CGI λ
-
Client Redirect with Document
client-redirdoc-response = client-Location Status Content-Type *other-field NL response-body
- CGI λ
Location
νλ κ°μ Client κ° λ¦¬λ€μ΄λ νΈ ν΄μΌν κ²½λ‘λ₯Ό μ μ΄μ£Όλ©°,Content-Type
μλ λ°ννλ λ¬Έμμ λ―Έλμ΄ νμ μ μλ €μ€λ€. - Server λ
302 Found
μν μ½λμ ν¨κ»Location
ν€λ νλλ₯Ό Client μκ² μ λ¬νλ©° Client κ° λ¦¬λ€μ΄λ μ μ μνν μ μκ² νλ€.
- CGI λ
- CGI μ μλ΅μ λ°μ Server λ CGI κ° λ³΄λΈ header νλλ€μ΄ μλ―Ένλ λ°κ° Server κ° μ€μ νλ μλ΅ ν€λ νλκ°κ³Ό μμΆ©λλ€λ©΄ μ΄λ€ κ°μ λ£μμ§ κ²°μ ν΄μΌνλ€.
- Server λ CGI μ μλ΅μ΄ HTTP κ·κ²©μ λ§λμ§ μ κ²νκ³ Client μκ² μ λ¬ν΄μΌνλ€.
- Server λ μ΄λ€ μν©μλ κΊΌμ§μ§ μμμΌνκ³ , HTTP/1.1 μ νΉμ± μ Connection keep-alive μ κ²½μ° κ°μ Connection κ°μ²΄κ° μ¬μ¬μ©λκΈ° λλ¬Έμ μμ μ λ¦¬κ° λ§€μ° μ€μνλ€.
- μ΅λν μμ ν λΉμ μμ±μμμ, ν΄μ λ μλ©Έμμμ μ²λ¦¬νλ€(RAII).
- νμ§λ§ μμ±κ³Ό μλ©Έ μ¬μ΄ν΄μ λ μ μκ³ λ°λ³΅μ μΌλ‘ μ¬μ¬μ©λλ κ°μ²΄μ κ²½μ° μλμ κΈ°λ³Έμ μΈ κ·μΉλ€μ μ£Όμνμ¬ μ§μΌμΌνλ€.
- heap use after free/double free/pointer being freed was not allocated λ₯Ό νΌνκΈ° μν΄ ν λΉ ν΄μ ν ν¬μΈν°
NULL
λ‘ μ€μ νλ€. - νμ λ
fd
ν μ΄λΈμ΄ μ¬μ¬μ©λκΈ° λλ¬Έμ socket, file, pipe μ I/O event μ μ¬μ©νλfd
κ° μ ν λ€λ₯Έ device λ₯Ό κ°λ¦¬ν¬ μ μλ€. μ΄λ₯Ό λ°©μ§νκΈ° μν΄ μ¬μ¬μ© λλfd
λ³μλ€μclose
μ΄ν -1 λ‘ μ€μ νλ€.
- heap use after free/double free/pointer being freed was not allocated λ₯Ό νΌνκΈ° μν΄ ν λΉ ν΄μ ν ν¬μΈν°
- Sockets (The GNU C Library)
- What is the meaning of SO_REUSEADDR (setsockopt option) - Linux?
- When is TCP option SO_LINGER (0) required?