패킷은 네트워크 스택(특히 L2, L3, L4)을 돌며 메타데이터가 채워지거나, 해석된다.
이번 페이지에서는 패킷이 도는 네트워크 스택 중 TCP(Transmission Control Protocol) layer(L4)에서 벌어지는 일들에 대해 알아보겠다.
네트워킹 스택과 관련된 레이어는 크게
가 있다.
그중 TCP 는 L4에 해당하는 layer이다. 그리고 네트워킹 스택 중에서 제일 복잡한 부분...이라고 한다.
TCP를 수행하는 이상적인 동작 과정(semantics)은
이다. 당연하겠지만, 이 모든 동작은 커널에 의해 보장된다. 구체적으로 TCP Header을 통해서 구체적으로 semantics가 실현된다.
TCP를 통해 server-client 간의 통신이 이루어질 때, 각 엔드포인트에는 '상태' 가 존재한다.
클라이언트는 패킷이 '얼마나 제대로' 전송됐는지 ACK를 통해 알려줌
ACK의 값은 TCP Header 안에 정의되어 있음.(ACK # = packet index)
만약 보낸 패킷의 수보다 받은 ACK number가 적게 들어오게 되면, 서버는 재전송.
이 값을 가지고 패킷의 order을 정렬할 수도 있음.
FYI) SACK (Selective ACK)
클라이언트 입장에서, 순차적으로 오다가, 중간에 한번 끊기고, 다시 순차적으로 오는 상황이 있을 수 있음.
ex) 1 2 X 4 5 (3 lost)
원래는 이럴 때 ACK로 2를 날리고, 서버는 3부터 다시 보낸다.
이렇게 된다면, 패킷 4 5를 굳이 안받아도 되는데 한번 더 받는 문제 발생(비효율적).
이것을 방지하기 위해, header의 option 필드에, SACK옵션으로 4 5 를 받았다는 정보를 담으면 서버는 오직 3만 보낸다.
클라이언트가 단위시간동안 받을 수 있는 최대 바이트 용량은 한정되어 있을 수밖에 없다.
이 최대 용량을 window size 라고 한다. 윈도우 사이즈는 고정값은 아니다. 소켓이나 커널의 파라미터 조정하면 조절 가능.
서버가 보낼 때, 클라이언트의 window size를 보고 보내야 할 패킷이 더 크다 싶으면 잠시 보내는 것을 정지한다.
두 컴퓨터 사이에는 병목현상이 발생할 수 있다. ex) 스위치나 라우터에 queue에 너무 많은 값이 저장되어 있을 경우.
이와 같은 경우, 보내는 양(sending rate) 자체를 조절해서 정체를 해소한다.
*어떻게 정체된걸 아는지?
ECN을 날려서 알려준다.*어떻게 조절하는지?
TCP는 소켓에서 struct sock (정확히는 struct sock을 포함한 struct tcp_sock)으로 구현된다.
sock의 개념을 다시 한번 언급하면, sock는 소켓의 PF(protocol family) 또는 프로토콜의 정보(metadata)를 담기 위한 구조체이다. 따라서, TCP 구현 또한 이 구조체로 실현된다.
그리고 이 sock 안의 receive queue 와 write queue안에 skb, 즉 패킷이 들어있다. 패킷은 헤더가 있고, TCP 소켓 안에 있는 패킷은 당연히 tcp header가 있다.
소켓을 생성하는 syscall은
int socket(int family, int type, int protocol) 이었다.
만약 TCP, IP 소켓을 하나 생성한다고 하면,
int socket(PF_INET, SOCK_STREAM, 0) (syscall) -> socket_create() -> __sock_create() -> inet_create() -> sk_alloc, sock_init_data(), tcp_v4_init_sock() 이 수행되어 struct tcp_sock이 만들어지게 된다.
이렇게 만들어진 tcp_sock 안에는 tcp를 위한 다양한 정보가 nested structure(중첩 구조체. 구조체 안에 구조체가 있음) 형태로 들어있다.
cf)
(most general) sock > inet_sock > inet_connection_sock > tcp_sock (most specific)
(tcp_sock 는 sock부터의 정보를 포함)

struct tcp_sockstruct inet_connection_sock : protocol congestion state, timer 등과 같은 정보를 담고 있음.
struct inet_sock : IP와 port 주소 정보를 담고 있음.
struct sock : receive queue, write queue 존재. queue에는 패킷이 들어있음. 패킷들은 queue에서 나갈 떄 TCP layer 단계를 거쳐감
* header of the TCP packet : struct tcphdr (include/uapi/linux/tcp.h 에 정의되어 있음)