네트워크 통신의 원리 (3) - 프로토콜 스택과 데이터 흐름 - soo:bak
작성일 :
규칙 없이는 통신할 수 없다
Part 1에서 물리적 신호 전송을, Part 2에서 디지털 데이터 처리를 살펴보았습니다.
이제 비트를 주고받을 수 있게 되었습니다.
하지만 비트를 전송할 수 있다는 것과 의미 있는 통신을 할 수 있다는 것은 다른 문제입니다.
두 컴퓨터가 통신한다고 해봅시다.
컴퓨터 A가 B에게 “11001010 01010011…“을 보냈습니다.
B는 이것을 어떻게 해석해야 할까요?
텍스트일까요? 이미지일까요? 동영상일까요?
데이터가 어디서 시작하고 어디서 끝나는지 어떻게 알까요?
이 데이터가 B를 위한 것인지, B를 경유해서 다른 곳으로 가는 것인지 어떻게 구분할까요?
규약(Protocol)이 필요합니다.
프로토콜은 통신의 규칙입니다.
데이터 형식, 순서, 오류 처리 방법, 주소 지정 방식 등을 정의합니다.
프로토콜 없이는 서로 다른 컴퓨터, 서로 다른 운영체제, 서로 다른 제조사의 장비가 통신할 수 없습니다.
왜 계층 구조인가
네트워크 통신은 복잡합니다.
물리적 신호 전송, 오류 검출, 주소 지정, 경로 선택, 데이터 순서 보장, 애플리케이션 프로토콜…
이 모든 것을 하나의 프로토콜로 처리하면 어떻게 될까요?
엄청나게 복잡해지고, 하나를 바꾸면 전체를 바꿔야 합니다.
해결책은 계층(Layer)으로 나누는 것입니다.
각 계층은 특정 기능만 담당합니다. 아래 계층이 제공하는 서비스를 사용하고, 자신의 기능을 위 계층에 서비스로 제공합니다.
이 구조의 핵심은 계층 간 독립성입니다.
웹 브라우저(응용 계층)는 데이터가 Wi-Fi로 전송되든 이더넷으로 전송되든 신경 쓰지 않습니다.
이더넷 카드(데이터링크 계층)는 그 위에서 TCP를 쓰든 UDP를 쓰든 상관하지 않습니다.
덕분에 기술을 독립적으로 발전시킬 수 있습니다.
Wi-Fi가 802.11n에서 802.11ac로, 다시 802.11ax(Wi-Fi 6)로 발전해도, 웹 브라우저를 수정할 필요가 없습니다.
HTTP가 1.1에서 2.0으로, 다시 3.0으로 발전해도, 이더넷 드라이버를 수정할 필요가 없습니다.
인터넷 프로토콜의 구조는 TCP/IP 4계층 모델로 설명됩니다.
1
2
3
4
5
6
7
응용 계층 (Application)
↓ ↑
전송 계층 (Transport)
↓ ↑
인터넷 계층 (Internet)
↓ ↑
네트워크 접근 계층 (Network Access)
데이터를 보낼 때는 위에서 아래로(↓), 받을 때는 아래에서 위로(↑) 흐릅니다.
각 계층이 어떤 문제를 해결하는지 살펴봅시다.
네트워크 접근 계층: 같은 네트워크 안에서
네트워크 접근 계층(Network Access Layer)은 같은 물리적 네트워크 안에서 데이터를 전달합니다. 이 계층은 실제 신호를 다루는 물리 계층(케이블, 무선)과 프레임 단위로 데이터를 주고받는 데이터링크 계층(MAC 주소)을 포함합니다.
비트 스트림을 프레임으로
Part 2에서 비트를 물리 신호로 변환하는 방법을 살펴보았습니다. 그런데 연속된 비트 스트림만으로는 어디가 데이터의 시작이고 끝인지 알 수 없습니다. 프레이밍(Framing)은 비트 스트림을 의미 있는 단위인 프레임(Frame)으로 나누는 것입니다.
이더넷 프레임의 구조는 다음과 같습니다.
1
2
3
4
5
┌─────────┬────────┬────────┬──────┬─────────────────┬─────┐
│프리앰블 │ 목적지 │ 출발지 │ 타입 │ 데이터 │ FCS │
│ (8) │ MAC(6) │ MAC(6) │ (2) │ (46-1500) │ (4) │
└─────────┴────────┴────────┴──────┴─────────────────┴─────┘
(바이트)
프리앰블(Preamble)은 10101010… 패턴으로, 수신측은 이 패턴을 감지하면 프레임이 시작됨을 알고 동기화를 맞춥니다. FCS(Frame Check Sequence)는 프레임 끝에 붙는 검사값으로, Part 2에서 다룬 CRC를 사용하여 프레임 손상 여부를 확인합니다.
MAC 주소: 누구에게 보내는가
같은 네트워크 안에 여러 장치가 있습니다. 프레임이 누구를 위한 것인지 구분하기 위해 MAC 주소(Media Access Control Address)를 사용합니다.
1
MAC 주소: 00:1A:2B:3C:4D:5E (48비트, 16진수 표기)
MAC 주소는 네트워크 인터페이스 카드(NIC)에 제조 시 부여됩니다. 앞 24비트(00:1A:2B)는 제조사 식별 코드이고, 뒤 24비트(3C:4D:5E)는 해당 제조사 내에서의 고유 번호입니다.
앞서 본 이더넷 프레임에는 목적지 MAC 주소와 출발지 MAC 주소가 포함됩니다. 프레임을 받은 장치는 목적지 MAC 주소가 자신의 주소와 일치하면 처리하고, 아니면 무시합니다.
브로드캐스트(Broadcast)
목적지 MAC 주소를 FF:FF:FF:FF:FF:FF로 설정하면 같은 네트워크의 모든 장치가 프레임을 받습니다. 특정 장치가 아닌 전체에게 메시지를 보낼 때 사용합니다.
스위치: MAC 주소로 전달
스위치가 없던 시절에는 허브(Hub)를 사용했습니다. 허브에는 네트워크 케이블을 꽂는 여러 개의 연결 단자가 있고, 각 단자에 컴퓨터를 연결합니다. 허브는 한 단자에서 프레임을 받으면 나머지 모든 단자로 전송합니다. 컴퓨터 A가 B에게 보내도, 같은 허브에 연결된 C, D, E 모두 이 프레임을 받습니다. 대역폭 낭비이고, 보안에도 좋지 않습니다.
스위치(Switch)는 MAC 주소를 보고 프레임을 해당 단자로만 전달합니다.
스위치는 처음에 어떤 컴퓨터가 어느 단자에 연결되어 있는지 모릅니다. 하지만 프레임이 오가는 것을 관찰하면서 배웁니다.
- 1번 단자에서 프레임이 들어옵니다
- 스위치는 프레임의 출발지 MAC 주소를 확인합니다
- “MAC 주소 00:1A:2B:3C:4D:5E는 1번 단자에 있다”고 테이블에 기록합니다
- 이제 목적지 MAC 주소를 테이블에서 찾습니다
- 찾으면 해당 단자로만 전송하고, 없으면 모든 단자로 전송합니다
시간이 지나면 테이블이 채워집니다.
1
2
3
4
MAC 주소 단자 번호
00:1A:2B:3C:4D:5E 1
00:AA:BB:CC:DD:EE 3
00:11:22:33:44:55 5
테이블이 완성되면 스위치는 프레임을 목적지 단자로만 전달할 수 있습니다.
인터넷 계층: 다른 네트워크로
MAC 주소는 같은 네트워크 안에서만 의미가 있습니다. 스위치는 자신에게 연결된 장치들의 MAC 주소만 알고 있기 때문입니다. 서울에 있는 컴퓨터가 뉴욕에 있는 서버와 통신하려면 중간에 수많은 네트워크를 거쳐야 합니다. 인터넷 계층(Internet Layer)이 이 역할을 담당합니다.
IP 주소: 논리적 주소
IP 주소(Internet Protocol Address)는 전 세계 네트워크에서 장치를 식별하는 논리적 주소입니다.
1
IPv4 주소: 192.168.1.100 (32비트)
MAC 주소는 하드웨어에 고정된 물리적 주소입니다. 반면 IP 주소는 네트워크 구성에 따라 할당됩니다. 예를 들어 노트북을 집에서 카페로 가져가면 MAC 주소는 그대로지만, IP 주소는 집에서 192.168.1.100이었다가 카페에서 192.168.0.50으로 바뀌는 방식입니다.
MAC 주소만으로는 다른 네트워크로 데이터를 보낼 수 없습니다. MAC 주소는 제조사가 순서대로 부여하기 때문에, 주소만 보고는 해당 장치가 어느 네트워크에 있는지 알 수 없습니다. 반면 IP 주소는 네트워크 부분과 호스트 부분으로 나뉘어 있어서, 주소만 보고도 어느 네트워크인지 알 수 있습니다. 이 구조 덕분에 여러 네트워크를 거쳐 목적지까지 경로를 찾는 라우팅(Routing)이 가능합니다.
1
2
3
192.168.1.100 (서브넷 마스크: 255.255.255.0)
192.168.1 . 100
←네트워크→ ←호스트→
라우터는 IP 주소의 네트워크 부분만 보고 방향을 결정합니다. 우편 시스템과 비슷합니다. 우체국은 전국의 모든 집 주소를 알 필요 없이 “서울 강남구로 가는 우편물은 이쪽으로” 정도만 알면 됩니다. 라우터도 “192.168.1.x로 가는 패킷은 이쪽으로”라는 정보만 가지고 있으면 됩니다.
IP 주소에 대한 자세한 내용은 IP 주소의 개념과 구조를 참조하세요.
IP 패킷
인터넷 계층의 데이터 단위는 패킷(Packet)입니다. IP 패킷에는 출발지 IP 주소와 목적지 IP 주소가 포함됩니다.
1
2
3
4
5
6
7
8
┌────────────────────────────────────────┐
│ IP 헤더 (20바이트~) │
│ 출발지 IP: 192.168.1.100 │
│ 목적지 IP: 142.250.196.110 (구글) │
│ TTL: 64, 프로토콜: TCP, ... │
├────────────────────────────────────────┤
│ 데이터 │
└────────────────────────────────────────┘
TTL(Time To Live)은 패킷이 네트워크에서 무한히 떠도는 것을 방지합니다. 라우터를 지날 때마다 TTL이 1씩 감소하고, 0이 되면 패킷은 폐기됩니다. 프로토콜 필드는 데이터 부분에 어떤 상위 계층 프로토콜(TCP, UDP 등)이 담겨 있는지 표시합니다.
라우터와 라우팅
라우터(Router)는 서로 다른 네트워크를 연결하는 장치입니다. 라우터는 패킷을 받으면 목적지 IP 주소를 확인하고, 라우팅 테이블을 참조하여 어느 방향으로 보낼지 결정합니다.
1
2
3
4
5
라우팅 테이블 예시:
목적지 네트워크 다음 홉(Next Hop) 출력 단자
192.168.1.0/24 직접 연결 eth0
10.0.0.0/8 192.168.1.1 eth0
0.0.0.0/0 203.0.113.1 eth1 (기본 경로)
홉(Hop)은 패킷이 라우터를 한 번 거치는 것을 말합니다. 다음 홉은 패킷을 전달할 바로 다음 라우터입니다. 라우팅 테이블은 “이 네트워크로 가려면 어느 다음 홉으로 보내라”는 정보를 담고 있습니다.
목적지 IP가 192.168.1.50이면 첫 번째 항목과 일치하므로 eth0 단자로 전송합니다. 어떤 항목과도 일치하지 않으면 기본 경로(0.0.0.0/0)로 보냅니다.
패킷이 서울에서 뉴욕까지 가는 과정은 다음과 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
내 PC (192.168.1.100)
↓
홈 라우터 (목적지가 내 네트워크가 아님 → ISP로)
↓
ISP 라우터 (목적지가 한국 내 아님 → 해외 경로로)
↓
여러 라우터를 거침 (해저 케이블, 국제 백본)
↓
미국 ISP 라우터
↓
목적지 네트워크 라우터
↓
목적지 서버 (142.250.196.110)
각 라우터는 전체 경로를 알지 못합니다. “이 목적지로 가려면 다음 홉은 어디인가”만 알면 됩니다. 모든 라우터가 전 세계의 모든 경로를 알 필요가 없으므로, 인터넷은 새로운 네트워크가 추가되어도 확장이 가능합니다.
ARP: IP 주소를 MAC 주소로
IP 패킷을 보내려면 프레임으로 캡슐화해야 하고, 프레임에는 목적지 MAC 주소가 필요합니다. 하지만 보통 목적지의 IP 주소만 알고 MAC 주소는 모릅니다. ARP(Address Resolution Protocol)가 IP 주소로 MAC 주소를 알아내는 역할을 합니다.
1
2
3
4
5
6
7
8
9
10
PC A가 192.168.1.20에게 데이터를 보내려 함
↓
A: "192.168.1.20의 MAC 주소는?"
(브로드캐스트로 네트워크 전체에 질문)
↓
IP가 192.168.1.20인 장치(B)만 응답:
B: "00:AA:BB:CC:DD:EE입니다"
(A에게만 응답)
↓
A는 이 정보를 저장해두고 이후 통신에 사용
ARP는 인터넷 계층(IP 주소)과 네트워크 접근 계층(MAC 주소) 사이를 연결합니다. IP 주소만으로는 실제 프레임을 보낼 수 없고, ARP를 통해 MAC 주소를 알아야 프레임을 완성할 수 있습니다.
DNS: 이름을 IP 주소로
사람은 142.250.196.110 같은 IP 주소 대신 www.google.com 같은 도메인 이름을 사용합니다. DNS(Domain Name System)가 도메인 이름을 IP 주소로 변환합니다. DNS 서버는 도메인 이름과 IP 주소의 매핑 정보를 저장하고 있는 서버로, 컴퓨터가 도메인 이름의 IP 주소를 물어보면 응답합니다.
1
2
3
4
5
6
7
브라우저: www.google.com 접속
↓
DNS 쿼리: "www.google.com의 IP는?"
↓
DNS 서버 응답: "142.250.196.110"
↓
브라우저: 142.250.196.110에 연결
DNS는 계층적 구조입니다. www.google.com을 찾을 때 루트 DNS 서버가 “.com은 이쪽에 물어봐”라고 알려주고, .com DNS 서버가 “google.com은 이쪽에 물어봐”라고 알려주는 방식으로 단계별로 찾아갑니다.
전송 계층: 종단간 통신
IP는 패킷을 목적지 컴퓨터까지 전달합니다. 하지만 컴퓨터에서는 웹 브라우저, 이메일, 카카오톡 등 여러 프로그램이 동시에 실행됩니다. 도착한 패킷이 어느 프로그램을 위한 것인지 구분해야 합니다. 전송 계층(Transport Layer)이 이 역할을 담당합니다.
포트 번호: 프로세스 구분
포트 번호(Port Number)는 같은 컴퓨터에서 실행되는 여러 프로세스를 구분합니다. IP 주소가 “어느 컴퓨터”를 지정한다면, 포트 번호는 “그 컴퓨터의 어느 프로세스”를 지정합니다.
1
2
3
4
IP 주소: 192.168.1.100 (어느 컴퓨터?)
포트: 80 (어느 프로세스?)
소켓 주소: 192.168.1.100:80
예를 들어 웹 서버 프로그램은 포트 80에서 대기합니다. 브라우저가 이 서버에 접속하면, 운영체제는 목적지 포트가 80인 패킷을 웹 서버 프로그램에 전달합니다.
포트 번호는 0~65535 범위입니다. 이 중 0~1023은 잘 알려진 포트(Well-known Ports)입니다. 특정 서비스가 어떤 포트를 사용할지 미리 약속해 둔 것입니다. 덕분에 브라우저는 웹 서버가 80번 포트에서 대기한다고 가정하고, 별도 설정 없이 접속할 수 있습니다.
1
2
3
4
22: SSH (원격 접속)
53: DNS (도메인 이름 조회)
80: HTTP (웹)
443: HTTPS (암호화된 웹)
TCP: 신뢰성 있는 전송
IP는 최선형(Best Effort) 서비스입니다. 패킷이 손실되거나, 순서가 뒤바뀌거나, 중복되어도 IP는 이를 해결하지 않습니다. 라우터가 모든 패킷의 순서와 도착 여부를 추적하면 처리 속도가 느려지기 때문입니다. IP는 패킷을 빠르게 전달하는 것에만 집중하고, 신뢰성은 양 끝단(TCP)에서 처리합니다. TCP(Transmission Control Protocol)가 이 문제를 해결하여 데이터가 손실 없이, 순서대로, 중복 없이 도착하도록 보장합니다.
연결 설정: 3-Way Handshake
TCP는 데이터를 보내기 전에 먼저 연결을 설정합니다.
1
2
3
4
5
6
7
8
9
10
11
12
클라이언트 서버
│ │
│───── SYN (seq=100) ──────────→ │
│ "연결하고 싶습니다" │
│ │
│←──── SYN+ACK (seq=300, ack=101) ──│
│ "좋습니다, 저도요" │
│ │
│───── ACK (ack=301) ──────────→ │
│ "확인했습니다" │
│ │
│ 연결 수립됨 │
SYN(Synchronize)과 ACK(Acknowledge)를 교환하여 양측이 통신 준비가 되었음을 확인합니다.
시퀀스 번호와 확인 응답
TCP는 보내는 모든 바이트에 시퀀스 번호(Sequence Number)를 부여합니다. 시퀀스 번호는 “이 데이터가 전체 스트림에서 몇 번째 바이트부터 시작하는지”를 나타냅니다. 수신측은 데이터를 받으면 확인 응답(ACK)으로 “다음에 몇 번째 바이트를 기대한다”고 알려줍니다.
1
2
3
4
5
6
7
8
9
10
11
송신자 수신자
│ │
│── seq=1000, 1000바이트 ──────────→ │
│ (1000번~1999번 바이트 전송) │ 수신 성공
│←──────── ack=2000 ───────────── │
│ (1999번까지 받음, 2000번 기대) │
│ │
│── seq=2000, 500바이트 ───────────→ │
│ (2000번~2499번 바이트 전송) │ 수신 성공
│←──────── ack=2500 ───────────── │
│ (2499번까지 받음, 2500번 기대) │
송신측은 ACK가 일정 시간 내에 오지 않으면 패킷이 손실되었다고 판단하고 재전송합니다. 이 방식으로 데이터 손실을 방지합니다.
패킷은 네트워크에서 서로 다른 경로로 전달될 수 있어서, 보낸 순서와 다르게 도착할 수 있습니다. 시퀀스 번호가 있으면 수신측은 도착 순서와 관계없이 원래 순서대로 데이터를 재조립할 수 있습니다.
흐름 제어
수신자가 데이터를 처리하는 속도는 상황에 따라 다릅니다. 다른 작업으로 바쁘거나 메모리가 부족하면 처리가 느려집니다. 송신자가 이를 무시하고 빠르게 보내면 수신자의 버퍼가 넘쳐서 데이터가 버려집니다.
TCP는 이를 방지하기 위해 수신자가 ACK를 보낼 때마다 “현재 N 바이트를 더 받을 수 있다”는 윈도우(Window) 크기를 함께 알려줍니다. 통신이 끝날 때까지 계속 교환되므로, 송신자는 수신자의 상태 변화에 맞춰 전송량을 조절할 수 있습니다.
혼잡 제어
흐름 제어가 수신자의 처리 속도에 맞추는 것이라면, 혼잡 제어는 네트워크의 처리 속도에 맞추는 것입니다.
많은 장치가 동시에 데이터를 보내면 라우터에 패킷이 몰립니다. 라우터의 대기열이 가득 차면 새로 도착하는 패킷을 버릴 수밖에 없습니다.
수신자가 바쁘면 윈도우 크기를 줄여서 명시적으로 알려주지만, 네트워크는 혼잡하다고 직접 알려주지 않습니다. TCP는 패킷 손실을 네트워크 혼잡의 신호로 해석합니다.
두 상황의 차이를 보면:
- 수신자가 바쁜 경우: ACK는 도착하지만 윈도우 크기가 작음 (예: “ACK, 윈도우=100”)
- 네트워크가 혼잡한 경우: ACK 자체가 도착하지 않음 (타임아웃 발생)
ACK가 오면 수신자 상태를 알 수 있고, ACK가 안 오면 네트워크 문제로 판단합니다.
패킷 손실이 발생하면 TCP는 전송 속도를 크게 줄입니다. 손실 없이 잘 전송되면 속도를 조금씩 높입니다. 줄일 때는 크게, 높일 때는 조금씩 조절하여 네트워크가 감당할 수 있는 최대 속도에 수렴합니다.
UDP: 빠른 전송
UDP(User Datagram Protocol)는 TCP와 다릅니다. 연결 설정 없이 바로 데이터를 보내고, 손실, 순서 변경, 중복에 대한 보장이 없습니다.
TCP와의 비교
TCP의 신뢰성에는 비용이 따릅니다. 3-Way Handshake로 연결을 설정하고, ACK를 기다리고, 손실 시 재전송합니다. UDP는 이 과정이 모두 없습니다. 데이터를 보내고 싶으면 그냥 보냅니다. 도착 여부는 확인하지 않습니다.
| TCP | UDP | |
|---|---|---|
| 연결 설정 | 필요 (3-Way Handshake) | 없음 |
| 신뢰성 | 보장 (재전송, 순서 정렬) | 없음 |
| 속도 | 상대적으로 느림 | 빠름 |
| 헤더 크기 | 20바이트 이상 | 8바이트 |
UDP가 적합한 경우
실시간 통신에서는 늦은 데이터보다 없는 데이터가 나을 수 있습니다. 화상 통화에서 0.5초 전 영상을 재전송 받아봐야 의미가 없습니다. 건너뛰고 현재 영상을 보여주는 것이 낫습니다.
- 실시간 스트리밍 (영상, 음성): 약간의 손실은 허용, 지연은 허용 불가
- 온라인 게임: 빠른 반응이 중요, 오래된 위치 정보는 무의미
- DNS 쿼리: 작은 데이터를 빠르게 주고받음, 실패하면 다시 요청
UDP 헤더 구조
1
2
3
4
5
┌─────────────────────────────────────────────┐
│ 출발지 포트 (16비트) │ 목적지 포트 (16비트) │
├─────────────────────────────────────────────┤
│ 길이 (16비트) │ 체크섬 (16비트) │
└─────────────────────────────────────────────┘
포트 번호, 데이터 길이, 오류 검사용 체크섬만 포함합니다. 시퀀스 번호, 윈도우 크기 등 신뢰성 관련 필드가 없으므로 헤더가 단순합니다.
신뢰성이 필요한 경우
UDP를 사용하면서도 신뢰성이 필요하면 애플리케이션이 직접 구현합니다. 예를 들어 QUIC 프로토콜은 UDP 위에서 동작하면서 자체적으로 재전송과 순서 보장 기능을 구현합니다. HTTP/3가 QUIC을 사용합니다.
응용 계층: 사용자와 만나다
전송 계층까지 오면 두 프로세스 간에 바이트 스트림을 주고받을 수 있습니다. 하지만 그 바이트가 무엇을 의미하는지, 어떤 형식으로 요청하고 응답하는지는 정해지지 않았습니다. 응용 계층(Application Layer)이 각 서비스에 맞는 데이터 형식과 통신 규칙을 정의합니다.
HTTP: 웹의 언어
HTTP(HyperText Transfer Protocol)는 웹에서 사용하는 프로토콜입니다. 클라이언트가 요청(Request)을 보내면 서버가 응답(Response)을 보내는 구조입니다.
HTTP 요청
1
2
3
4
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
첫 줄에는 메서드(GET), 경로(/index.html), 버전(HTTP/1.1)이 있습니다. 그 아래 헤더에는 호스트, 브라우저 종류, 원하는 형식 등 추가 정보가 들어갑니다.
HTTP 응답
1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<!DOCTYPE html>
<html>
...
</html>
첫 줄에 상태 코드(200 OK)가 있고, 헤더에 콘텐츠 종류와 길이가 있으며, 빈 줄 이후에 실제 데이터(본문)가 옵니다.
무상태 프로토콜
HTTP는 무상태(Stateless) 프로토콜입니다. 서버는 이전 요청을 기억하지 않고 각 요청을 독립적으로 처리합니다. 무상태로 설계한 이유는 서버 구현이 단순해지고, 요청마다 다른 서버가 처리해도 되므로 확장이 쉽기 때문입니다.
하지만 로그인 상태나 장바구니처럼 여러 요청에 걸쳐 유지해야 하는 정보가 있습니다. 이를 위해 쿠키(Cookie)와 세션(Session)을 사용합니다.
쿠키(Cookie)
쿠키는 서버가 클라이언트(브라우저)에게 저장하라고 전달하는 작은 데이터입니다.
1
2
3
4
5
# 서버 → 클라이언트 (응답 헤더)
Set-Cookie: user_id=abc123; Expires=Wed, 09 Jun 2025 10:18:14 GMT
# 클라이언트 → 서버 (다음 요청 헤더)
Cookie: user_id=abc123
서버가 Set-Cookie 헤더로 쿠키를 설정하면, 브라우저는 이를 저장합니다. 이후 같은 서버에 요청할 때마다 브라우저가 자동으로 Cookie 헤더에 담아 보냅니다. 서버는 이 쿠키를 보고 사용자를 식별합니다.
쿠키에는 여러 속성을 설정할 수 있습니다:
Expires/Max-Age: 만료 시간. 없으면 브라우저 종료 시 삭제됨Path: 이 경로에 요청할 때만 쿠키 전송Secure: HTTPS 연결에서만 전송HttpOnly: JavaScript에서 접근 불가 (보안 강화)
세션(Session)
쿠키에 민감한 정보(비밀번호, 개인정보)를 직접 저장하면 위험합니다. 클라이언트에 저장되므로 조작이나 탈취가 가능하기 때문입니다.
세션은 이 문제를 해결합니다. 실제 데이터는 서버에 저장하고, 클라이언트에는 세션 ID(임의의 긴 문자열)만 쿠키로 전달합니다.
1
2
3
4
5
6
7
8
# 서버 → 클라이언트
Set-Cookie: session_id=x7k9m2p4q8w1e5r3t6y0
# 서버 내부 저장소
session_id: x7k9m2p4q8w1e5r3t6y0
→ user_id: 42
→ username: "홍길동"
→ is_authenticated: true
클라이언트가 세션 ID를 보내면, 서버는 이 ID로 저장소를 조회하여 해당 사용자의 정보를 가져옵니다. 민감한 데이터가 네트워크를 통해 전송되지 않으므로 더 안전합니다.
세션 데이터는 서버 메모리, 데이터베이스, Redis 같은 저장소에 보관합니다. 사용자가 로그아웃하거나 일정 시간이 지나면 세션이 만료됩니다.
HTTPS: 암호화된 HTTP
HTTP는 데이터를 평문으로 전송합니다. 네트워크 경로 상의 누구나(같은 Wi-Fi 사용자, ISP, 라우터 관리자 등) 내용을 읽을 수 있습니다. 로그인 정보나 개인정보가 그대로 노출될 수 있습니다.
HTTPS(HTTP Secure)는 HTTP에 TLS(Transport Layer Security)를 추가하여 두 가지 문제를 해결합니다.
첫째, 암호화입니다. 클라이언트와 서버가 암호화 키를 교환한 뒤, 모든 데이터를 암호화하여 전송합니다. 중간에서 패킷을 가로채도 내용을 해독할 수 없습니다.
둘째, 인증입니다. 서버는 인증 기관(CA)이 발급한 인증서를 제시합니다. 브라우저는 이 인증서를 검증하여 접속한 서버가 실제로 해당 도메인의 소유자인지 확인합니다. 이를 통해 공격자가 가짜 서버로 트래픽을 유도하는 것을 방지합니다.
브라우저 주소창의 자물쇠 아이콘이 HTTPS 연결을 의미합니다. 현대 웹에서는 HTTPS가 기본이며, 많은 브라우저가 HTTP 사이트에 “안전하지 않음” 경고를 표시합니다.
캡슐화: 계층을 내려가며
데이터가 송신측에서 수신측으로 전달되는 과정을 따라가 봅시다.
응용 계층에서 HTTP 요청을 생성합니다.
1
GET /index.html HTTP/1.1...
전송 계층은 이 데이터에 헤더를 붙입니다. TCP는 세그먼트(Segment), UDP는 데이터그램(Datagram)이라고 부릅니다.
HTTP는 데이터가 손실되거나 순서가 바뀌면 페이지가 제대로 표시되지 않으므로 신뢰성 있는 TCP를 사용합니다. TCP 헤더(출발지/목적지 포트, 시퀀스 번호 등)를 앞에 붙입니다.
1
[TCP 헤더][HTTP 요청]
인터넷 계층(IP)은 세그먼트를 받아 패킷(Packet)을 만듭니다. IP 헤더(출발지/목적지 IP, TTL 등)를 앞에 붙입니다.
1
[IP 헤더][TCP 헤더][HTTP 요청]
네트워크 접근 계층(이더넷)은 패킷을 받아 프레임(Frame)을 만듭니다. 이더넷 헤더(출발지/목적지 MAC)를 앞에, FCS를 뒤에 붙입니다.
1
[이더넷 헤더][IP 헤더][TCP 헤더][HTTP 요청][FCS]
물리 계층에서 프레임은 비트로 변환되어 전기 신호나 빛으로 전송됩니다.
이 과정을 캡슐화(Encapsulation)라고 합니다. 각 계층이 자신의 헤더를 추가하여 상위 계층의 데이터를 감싸는 방식입니다.
1
2
3
4
응용: [ HTTP 요청 ]
전송: [TCP 헤더][ HTTP 요청 ]
네트워크: [IP 헤더][TCP 헤더][HTTP 요청]
링크: [Eth 헤더][IP][TCP][HTTP][FCS]
수신측에서는 반대로 역캡슐화(Decapsulation)가 일어납니다. 각 계층에서 자신의 헤더를 확인하고 제거하여, 최종적으로 응용 계층은 원래의 HTTP 요청만 받습니다.
전체 흐름: URL을 입력하면
지금까지 살펴본 내용을 종합하여, 브라우저에서 https://www.google.com을 입력했을 때 일어나는 과정을 따라가 봅시다.
1. DNS 조회
브라우저는 www.google.com의 IP 주소를 모르므로 DNS 서버에 질의합니다.
1
"www.google.com의 IP는?" → "142.250.196.110"
2. TCP 연결
브라우저는 142.250.196.110의 포트 443에 TCP 연결을 요청합니다. 3-Way Handshake로 연결을 수립합니다.
3. TLS 핸드셰이크
HTTPS이므로 TLS 연결을 설정합니다. 암호화 방식 협상, 서버 인증서 확인, 세션 키 교환이 일어납니다.
4. HTTP 요청
암호화된 채널을 통해 HTTP GET 요청을 보냅니다.
1
2
GET / HTTP/1.1
Host: www.google.com
5. 캡슐화
HTTP 요청이 각 계층을 거치며 헤더가 추가됩니다.
1
2
3
4
5
6
7
8
9
응용: GET / HTTP/1.1 ...
↓
TCP: 세그먼트 (출발지 포트: 52000, 목적지 포트: 443)
↓
IP: 패킷 (출발지: 192.168.1.100, 목적지: 142.250.196.110)
↓
이더넷: 프레임 (목적지 MAC: 게이트웨이 MAC)
↓
물리: 비트 → 전기 신호
6. 라우팅
프레임이 홈 라우터로 전송됩니다. 라우터는 IP 헤더를 보고 다음 홉을 결정하고, 여러 라우터를 거쳐 구글 서버까지 도달합니다.
7. 서버 응답
구글 서버는 패킷을 받아 역캡슐화하고, HTTP 요청을 처리하여 HTML 응답을 생성합니다. 응답은 같은 과정을 거쳐 브라우저로 돌아옵니다.
8. 렌더링
브라우저는 HTML을 파싱하고 화면에 표시합니다. 추가 리소스(이미지, CSS, JavaScript)가 필요하면 각각에 대해 이 과정을 반복합니다.
이 모든 과정이 순식간에 일어나서, 사용자는 그냥 구글 페이지가 뜨는 것만 봅니다.
마무리: 계층이 만드는 통신
네트워크 통신은 계층적 프로토콜 스택으로 구성됩니다. 각 계층의 역할을 정리하면:
- 네트워크 접근 계층: 같은 네트워크 내에서 MAC 주소로 프레임을 전달
- 인터넷 계층: IP 주소로 서로 다른 네트워크 간에 패킷을 라우팅
- 전송 계층: 포트 번호로 프로세스를 구분하고, TCP는 신뢰성을, UDP는 속도를 제공
- 응용 계층: HTTP, DNS 등 각 서비스에 맞는 프로토콜을 정의
캡슐화와 역캡슐화를 통해 각 계층은 독립적으로 동작합니다. 위 계층은 아래 계층의 구현을 몰라도 되고, 아래 계층은 위 계층의 내용을 해석하지 않아도 됩니다.
이 시리즈에서 살펴본 내용을 종합하면: Part 1의 물리적 신호 전송이 비트를 실어 나르고, Part 2의 디지털 처리가 그 비트를 신뢰할 수 있게 만들고, Part 3의 프로토콜 스택이 그 비트들을 의미 있는 통신으로 조직합니다.
전자기파의 물리 법칙부터 HTTP 요청까지, 모든 계층이 협력하여 인터넷이 동작합니다.
관련 글
- 네트워크 통신의 원리 (1) - 전자기파와 신호 전송
- 네트워크 통신의 원리 (2) - 디지털 신호와 정보 전달
- IP 주소(IP Address)의 개념과 구조
- 서브넷(Subnet)의 개념과 서브네팅
심화 시리즈
- 소켓과 전송 계층 (1) - 소켓의 탄생과 추상화
- 소켓과 전송 계층 (2) - TCP 연결의 상태 머신
- 소켓과 전송 계층 (3) - 멀티플렉싱과 패킷 흐름
- 무선 통신의 진화 (1) - 무선 채널의 물리적 특성
- 무선 통신의 진화 (2) - 셀룰러와 Wi-Fi의 발전
- 라우팅과 인터넷 구조 (1) - 라우팅의 역사와 기본 원리
- 라우팅과 인터넷 구조 (2) - 거리 벡터와 링크 상태 알고리즘
- 라우팅과 인터넷 구조 (3) - BGP와 인터넷의 구조
- 네트워크 보안의 원리 (1) - 암호화의 수학적 기초
- 네트워크 보안의 원리 (2) - TLS와 인증서 체계
- 네트워크 보안의 원리 (3) - 네트워크 공격과 방어
- HTTP의 진화 (1) - HTTP/1.0에서 HTTP/2까지
- HTTP의 진화 (2) - HTTP/3과 QUIC, 그리고 WebSocket
- DNS의 원리 (1) - DNS의 탄생과 계층 구조
- DNS의 원리 (2) - DNS 질의와 해석 과정
- DNS의 원리 (3) - DNS 보안과 현대적 발전
- NAT와 방화벽 (1) - NAT의 탄생과 주소 변환
- NAT와 방화벽 (2) - 방화벽과 상태 추적
- NAT와 방화벽 (3) - NAT 트래버설과 P2P
- VPN과 터널링 (1) - 터널링의 원리
- VPN과 터널링 (2) - IPsec의 구조
- VPN과 터널링 (3) - 현대 VPN 기술
- 로드 밸런싱 (1) - 로드 밸런싱의 원리
- 로드 밸런싱 (2) - DNS 기반 로드 밸런싱
- 로드 밸런싱 (3) - 고가용성 아키텍처
- 컨테이너 네트워킹 (1) - 컨테이너 네트워크 기초
- 컨테이너 네트워킹 (2) - 오버레이 네트워크
- 컨테이너 네트워킹 (3) - Kubernetes 네트워킹
- 네트워크 성능 (1) - 지연 시간의 구성 요소
- 네트워크 성능 (2) - TCP 혼잡 제어 심화
- 네트워크 성능 (3) - 애플리케이션 레벨 최적화
- 실시간 통신 (1) - RTP와 실시간 전송
- 실시간 통신 (2) - WebRTC 스택
- 실시간 통신 (3) - 품질 관리와 적응
- 네트워크 디버깅 (1) - 계층별 진단 도구
- 네트워크 디버깅 (2) - 패킷 분석
- IoT 네트워킹 (1) - IoT 프로토콜
- IoT 네트워킹 (2) - LPWAN과 IoT 보안