[CS] 네트워크
작성자 : 오예환 | 작성일 : 2025-12-18 | 수정일 : 2025-12-18
1. 네트워크 기초
네트워크란?
네트워크(Network)는 노드(Node) 와 링크(Link) 가 서로 연결되어 리소스를 공유하는 집합을 의미합니다.
- 노드: 서버, 라우터, 스위치 등 네트워크 장치
- 링크: 유선 또는 무선과 같은 연결 매체
처리량(Throughput)과 지연 시간(Latency)
처리량 (Throughput)
- 단위 시간당 전송되는 데이터의 양
- 단위: bps (bits per second), Mbps, Gbps
- 영향 요소: 대역폭, 네트워크 혼잡도, 패킷 손실
지연 시간 (Latency)
- 요청이 처리되는 데 걸리는 시간
- 구성 요소:
- 전파 지연: 신호가 매체를 통해 이동하는 시간
- 전송 지연: 패킷을 링크에 밀어넣는 시간
- 처리 지연: 라우터가 패킷을 처리하는 시간
- 큐잉 지연: 패킷이 큐에서 대기하는 시간
네트워크 토폴로지 (Network Topology)
네트워크의 물리적 또는 논리적 연결 구조입니다.
| 토폴로지 | 특징 | 장점 | 단점 |
|---|---|---|---|
| 스타(Star) | 중앙 노드에 모든 노드 연결 | 장애 격리 용이 | 중앙 노드 장애 시 전체 마비 |
| 링(Ring) | 노드들이 원형으로 연결 | 단방향 전송으로 충돌 없음 | 한 노드 장애 시 전체 영향 |
| 버스(Bus) | 하나의 통신 회선에 모든 노드 연결 | 설치 비용 저렴 | 충돌 발생 가능, 보안 취약 |
| 트리(Tree) | 계층적 구조 | 확장 용이 | 루트 노드 장애 시 문제 |
| 메시(Mesh) | 모든 노드가 서로 연결 | 높은 안정성 | 비용 높음, 관리 복잡 |
병목 현상 (Bottleneck)
전체 시스템의 성능이 가장 느린 구간에 의해 제한되는 현상입니다.
- 발생 원인: 대역폭 부족, 서버 과부하, 네트워크 혼잡
- 해결 방법:
- 네트워크 대역폭 증설
- 로드 밸런싱
- 캐싱 적용
- 트래픽 분산 (CDN)
2. TCP/IP 4계층 모델
인터넷 프로토콜 스위트 (Internet Protocol Suite)
인터넷 프로토콜 스위트는 인터넷에서 컴퓨터들이 서로 정보를 주고받는 데 사용하는 프로토콜의 집합입니다.
이 프로토콜 집합을 설명하는 대표적인 모델이 두 가지 있습니다:
| 모델 | 설명 |
|---|---|
| OSI 7계층 | Open Systems Interconnection. ISO에서 만든 이론적/표준 참조 모델 |
| TCP/IP 4계층 | 실제 인터넷에서 사용되는 실용적인 모델 |
왜 계층을 나눌까?
네트워크 통신은 매우 복잡한 과정입니다. 이를 역할별로 계층을 나누어 관리하면:
- 복잡성 감소: 각 계층은 자신의 역할에만 집중
- 독립적 개발: 한 계층을 수정해도 다른 계층에 영향 없음
- 표준화 용이: 계층별로 표준 프로토콜 정의 가능
쉽게 말해, 택배 시스템과 비슷합니다:
- 물건 포장 담당 (애플리케이션 계층)
- 배송 경로 결정 담당 (인터넷 계층)
- 실제 운송 담당 (네트워크 접근 계층)
각 담당자는 자기 역할만 잘 하면 되고, 다른 담당자가 어떻게 일하는지 몰라도 됩니다.
OSI 7계층 vs TCP/IP 4계층
OSI = Open Systems Interconnection (개방형 시스템 간 상호 연결)
OSI 7계층 TCP/IP 4계층
─────────────────────────────────────────
7. 응용 계층 (Application) ┐
6. 표현 계층 (Presentation) ├→ 4. 애플리케이션 계층
5. 세션 계층 (Session) ┘
4. 전송 계층 (Transport) → 3. 전송 계층
3. 네트워크 계층 (Network) → 2. 인터넷 계층
2. 데이터링크 계층 (Data Link)┐
1. 물리 계층 (Physical) ┘→ 1. 네트워크 접근 계층
OSI는 이론적 표준, TCP/IP는 실제 인터넷의 구현 모델입니다. 면접에서는 주로 TCP/IP 4계층을 기준으로 설명합니다.
2.1 애플리케이션 계층 (Application Layer)
응용 프로그램이 사용하는 프로토콜 계층입니다.
| 프로토콜 | 포트 | 설명 |
|---|---|---|
| HTTP/HTTPS | 80/443 | 웹 통신 |
| FTP | 20/21 | 파일 전송 |
| SMTP | 25 | 이메일 전송 |
| DNS | 53 | 도메인 이름 → IP 주소 변환 |
| SSH | 22 | 보안 원격 접속 |
2.2 전송 계층 (Transport Layer)
송신자와 수신자 간의 신뢰성 있는 데이터 전송을 담당합니다.
패킷 교환 방식
네트워크에서 데이터를 전송할 때 패킷이라는 작은 단위로 나누어 보냅니다. 이 패킷을 전달하는 방식에는 두 가지가 있습니다.
가상회선 패킷 교환 (Virtual Circuit)
[송신자] ──→ [라우터A] ──→ [라우터B] ──→ [라우터C] ──→ [수신자]
│ │ │
패킷1,2,3 → 패킷1,2,3 → 패킷1,2,3 →
(같은 경로) (같은 경로) (같은 경로)
- 통신 전에 미리 경로를 설정하고, 모든 패킷이 같은 경로로 전송
- 패킷이 순서대로 도착
- TCP가 이 방식을 사용
데이터그램 패킷 교환 (Datagram)
[송신자] ──→ [라우터A] ──→ [라우터B] ──→ [수신자]
│ ↗
└──→ [라우터D] ──→ [라우터E]
(패킷마다 다른 경로 가능)
- 각 패킷이 독립적으로 최적의 경로를 선택
- 패킷이 순서 없이 도착할 수 있음
- UDP가 이 방식을 사용
| 구분 | 가상회선 (TCP) | 데이터그램 (UDP) |
|---|---|---|
| 연결 설정 | 필요 | 불필요 |
| 경로 | 고정 | 패킷마다 다름 |
| 순서 보장 | O | X |
| 신뢰성 | 높음 | 낮음 |
| 오버헤드 | 큼 | 작음 |
TCP vs UDP
| 구분 | TCP | UDP |
|---|---|---|
| 연결 방식 | 연결 지향 (Connection-oriented) | 비연결 (Connectionless) |
| 신뢰성 | 높음 (재전송, 순서 보장) | 낮음 |
| 속도 | 상대적으로 느림 | 빠름 |
| 헤더 크기 | 20~60 bytes | 8 bytes |
| 사용 예시 | HTTP, 이메일, 파일 전송 | 스트리밍, 게임, DNS |
3-way Handshake (TCP 연결 수립)
Client Server
│ │
│──── SYN (seq=x) ───────→│
│ │
│←── SYN-ACK (seq=y, ack=x+1) ──│
│ │
│──── ACK (ack=y+1) ─────→│
│ │
│ 연결 수립 완료 │
- SYN: 클라이언트가 서버에 연결 요청 (시퀀스 번호 전송)
- SYN-ACK: 서버가 요청 수락 + 자신의 시퀀스 번호 전송
- ACK: 클라이언트가 확인 응답
왜 3-way Handshake가 신뢰성을 보장할까?
3-way handshake 자체는 "연결 수립"만 담당합니다. TCP의 신뢰성은 handshake가 아니라 연결 후 데이터 전송 과정에서 보장됩니다.
3-way handshake가 하는 일:
- 양쪽이 서로 통신 가능한 상태인지 확인
- 시퀀스 번호 동기화 (데이터 순서 추적을 위한 시작점 설정)
실제 신뢰성을 보장하는 메커니즘:
| 메커니즘 | 설명 |
|---|---|
| ACK (확인 응답) | 데이터를 받으면 "받았다"고 응답. 응답이 없으면 재전송 |
| 시퀀스 번호 | 각 데이터에 번호를 붙여 순서대로 조립 가능 |
| 재전송 타이머 | 일정 시간 내 ACK가 없으면 자동으로 재전송 |
| 체크섬 | 데이터 손상 여부 검사 |
[신뢰성 있는 전송 예시]
Client Server
│ │
│──── 데이터1 (seq=100) ──────→│
│ │ ← 받음
│←──── ACK (ack=101) ──────────│
│ │
│──── 데이터2 (seq=101) ──────→│
│ ✕ (손실) │
│ │
│ (타임아웃, ACK 안 옴) │
│ │
│──── 데이터2 (seq=101) ──────→│ ← 재전송!
│ │
│←──── ACK (ack=102) ──────────│
즉, 3-way handshake는 "신뢰성 있는 통신을 위한 준비 단계" 이고, 실제 신뢰성은 ACK + 재전송 + 순서 보장으로 구현됩니다.
ACK는 양방향
TCP는 양방향(Full-duplex) 통신이기 때문에, 데이터를 받는 쪽이 항상 ACK를 보냅니다.
[클라이언트 → 서버 데이터 전송]
Client Server
│ │
│──── 데이터 (seq=100) ───────→│
│ │ ← 서버가 받음
│←──── ACK (ack=101) ──────────│ ← 서버가 ACK 전송
[서버 → 클라이언트 데이터 전송]
Client Server
│ │
│←──── 데이터 (seq=200) ───────│ ← 서버가 보냄
│ │
│──── ACK (ack=201) ───────────→│ ← 클라이언트가 ACK 전송
- 클라이언트가 데이터를 보내면 → 서버가 ACK
- 서버가 데이터를 보내면 → 클라이언트가 ACK
ACK는 "누가 클라이언트/서버인가"와 무관하게, 데이터를 받은 쪽이 보내는 것입니다.
FIN은 언제 보내는가?
FIN 패킷은 자동으로 일정 시간 후에 보내는 것이 아니라, 애플리케이션이 명시적으로 연결 종료를 요청할 때 보냅니다.
// Node.js 예시
socket.end(); // 이 순간 FIN 패킷이 전송됨
socket.destroy(); // 강제 종료
// 브라우저에서
ws.close(); // WebSocket 종료 시 FIN 전송프로토콜별 FIN 전송 시점:
| 프로토콜 | FIN 전송 시점 |
|---|---|
| HTTP/1.0 | 응답 완료 후 바로 (매 요청마다 연결 종료) |
| HTTP/1.1 | Keep-Alive 타임아웃 후, 또는 Connection: close 헤더 시 |
| WebSocket | ws.close() 호출 시 |
| 일반 TCP | socket.end() 또는 close() 호출 시 |
핵심: FIN은 타이머가 아닌 이벤트 기반입니다. 애플리케이션이 "더 이상 보낼 데이터가 없다"고 결정했을 때 운영체제에 알리면, 그때 FIN이 전송됩니다.
4-way Handshake (TCP 연결 종료)
Client Server
│ │
│──── FIN ───────────────→│ (1) 클라이언트: "나 보낼 거 다 보냄"
│ │
│←──── ACK ───────────────│ (2) 서버: "알겠어"
│ │
│←──── FIN ───────────────│ (3) 서버: "나도 보낼 거 다 보냄"
│ │
│──── ACK ───────────────→│ (4) 클라이언트: "알겠어"
│ │
│ [TIME_WAIT 상태] │
│ (일정 시간 대기) │
│ │
│ 연결 종료 완료 │
TIME_WAIT 상태는 왜 필요할까?
클라이언트는 마지막 ACK를 보낸 후 바로 연결을 닫지 않고, 일정 시간(보통 2MSL, 약 60초) 동안 TIME_WAIT 상태로 대기합니다.
이유 1: 마지막 ACK 손실 대비
Client Server
│ │
│──── ACK ───────────────→│
│ ✕ (손실) │
│ │
│ (클라이언트가 바로 종료하면?)
│ │
│←──── FIN (재전송) ──────│ ← 서버: "ACK 안 왔네, 다시 보내자"
│ ✕ (받을 수 없음) │
│ │
│ 서버는 영원히 FIN 재전송...
TIME_WAIT 상태에서 대기하면:
Client Server
│ │
│──── ACK ───────────────→│
│ ✕ (손실) │
│ │
│ [TIME_WAIT 대기 중] │
│ │
│←──── FIN (재전송) ──────│ ← 서버가 다시 보냄
│ │
│──── ACK (재전송) ───────→│ ← 클라이언트가 다시 응답!
│ │
│ 정상 종료 │
이유 2: 지연된 패킷 처리
네트워크에서 지연된 이전 연결의 패킷이 새 연결에 영향을 주는 것을 방지합니다.
[시나리오: TIME_WAIT 없이 바로 같은 포트로 새 연결을 맺으면]
이전 연결의 지연된 패킷 ──→ 새 연결이 받아버림 (데이터 오염!)
TIME_WAIT 동안 대기하면 이전 연결의 모든 패킷이 네트워크에서 사라지므로, 새 연결이 오염되지 않습니다.
| 항목 | 설명 |
|---|---|
| 대기 시간 | 2 × MSL (Maximum Segment Lifetime), 보통 60초 |
| MSL | 패킷이 네트워크에서 살아있을 수 있는 최대 시간 |
| 목적 | ACK 손실 대비 + 지연 패킷 처리 |
TCP 흐름 제어 (Flow Control)
수신자의 버퍼 오버플로우를 방지하기 위해 송신 속도를 조절합니다.
- 슬라이딩 윈도우: 수신 윈도우 크기만큼만 데이터 전송
- 수신자가 윈도우 크기를 ACK에 포함하여 알림
TCP 혼잡 제어 (Congestion Control)
네트워크 혼잡을 방지하기 위한 메커니즘입니다.
- AIMD: 패킷 손실 전까지 윈도우 증가, 손실 시 절반으로 감소
- Slow Start: 초기에 윈도우를 1부터 지수적으로 증가
- 혼잡 회피: 임계점 도달 후 선형적으로 증가
2.3 인터넷 계층 (Internet Layer)
패킷을 목적지까지 라우팅하는 역할을 합니다.
| 프로토콜 | 설명 |
|---|---|
| IP | 논리적 주소 지정 및 패킷 전달 |
| ICMP | 오류 메시지 전송 (ping 등) |
| ARP | IP 주소 → MAC 주소 변환 |
| RARP | MAC 주소 → IP 주소 변환 |
2.4 네트워크 접근 계층 (Network Access Layer)
실제 데이터 전송을 담당합니다.
- 이더넷 (Ethernet): 유선 LAN의 표준 프로토콜
- Wi-Fi: 무선 LAN 프로토콜 (IEEE 802.11)
- MAC 주소: 48비트 물리적 주소 (예:
00:1A:2B:3C:4D:5E)
실제 예시: 브라우저에서 www.google.com 접속하기
브라우저에서 웹사이트에 접속할 때, 4계층이 순차적으로 실행되는 것이 아니라 매 패킷마다 4계층 전체를 통과합니다.
각 계층의 역할
| 계층 | 역할 | 추가하는 정보 |
|---|---|---|
| 애플리케이션 | "무엇을" 요청할지 결정 | HTTP 요청 (GET /) |
| 전송 | "어떻게" 안전하게 전달할지 | 포트 번호, 순서 번호 |
| 인터넷 | "어디로" 보낼지 | IP 주소 |
| 네트워크 접근 | "실제로" 전송 | MAC 주소, 전기 신호 |
실제 통신 흐름
1. TCP 연결 수립 (3-way handshake)
SYN 패킷 하나를 보내려면 4계층 전체를 거칩니다:
[SYN 패킷 전송]
TCP: SYN 플래그 설정, 포트 443
↓
IP: 출발지 192.168.0.10, 목적지 142.250.196.110 (Google)
↓
이더넷: 출발지 MAC, 목적지 MAC (공유기)
↓
전기/무선 신호로 전송
SYN-ACK, ACK도 마찬가지로 각각 4계층 전체를 왕복합니다.
2. HTTP 요청 전송
TCP 연결이 수립된 후, HTTP 데이터를 보낼 때도 동일합니다:
[HTTP 요청]
애플리케이션: GET / HTTP/1.1, Host: www.google.com
↓
TCP: 세그먼트로 분할, 포트 443, 순서 번호 부여
↓
IP: IP 헤더 추가 (출발지/목적지 IP)
↓
이더넷: 프레임으로 포장 (MAC 주소)
↓
전송
3. 캡슐화와 역캡슐화
각 계층에서 헤더가 추가되면서 데이터 단위의 명칭이 바뀝니다.
| 계층 | 추가되는 것 | 데이터 단위 명칭 |
|---|---|---|
| 애플리케이션 | - | 데이터 (Data) |
| 전송 | TCP/UDP 헤더 | 세그먼트 (TCP) / 데이터그램 (UDP) |
| 인터넷 | IP 헤더 | 패킷 (Packet) |
| 네트워크 접근 | 이더넷 헤더 + 트레일러(FCS) | 프레임 (Frame) |
[송신 - 캡슐화]
HTTP 데이터
↓ TCP 헤더 추가
[TCP Header][HTTP 데이터] ← 세그먼트
↓ IP 헤더 추가
[IP Header][TCP Header][HTTP 데이터] ← 패킷
↓ 이더넷 헤더 + 트레일러 추가
[Ethernet Header][IP][TCP][HTTP 데이터][FCS] ← 프레임
[수신 - 역캡슐화]
프레임 → 패킷 → 세그먼트 → 데이터
(각 계층에서 헤더/트레일러 제거)
**FCS (Frame Check Sequence)**는 프레임에만 붙는 트레일러로, 물리 계층에서 전송 중 발생한 오류를 검출하기 위해 사용됩니다.
**핵심**: 계층은 "순서"가 아니라 "역할 분담"입니다. 모든 패킷(SYN, ACK, HTTP 데이터 등)은 전송될 때마다 4계층 전체를 통과합니다.
3. 네트워크 기기
계층별 네트워크 장비
계층 7 ─ 응용 ────────── L7 스위치 (로드밸런서)
계층 4 ─ 전송 ────────── L4 스위치 (로드밸런서)
계층 3 ─ 네트워크 ────── 라우터, L3 스위치
계층 2 ─ 데이터링크 ──── 브리지, L2 스위치
계층 1 ─ 물리 ────────── 리피터, 허브
물리 계층 장비
리피터 (Repeater)
- 약해진 신호를 증폭하여 전달
- 단순 신호 복원만 수행
허브 (Hub)
- 여러 장비를 연결하는 멀티포트 리피터
- 받은 데이터를 모든 포트로 전송 (브로드캐스트)
- 충돌 도메인을 공유하여 비효율적
데이터 링크 계층 장비
브리지 (Bridge)
- MAC 주소를 학습하여 프레임 필터링
- 충돌 도메인을 분리
스위치 (L2 Switch)
- 브리지의 발전형
- MAC 주소 테이블을 기반으로 목적지 포트로만 전송
- 전이중(Full-duplex) 통신 지원
네트워크 계층 장비
라우터 (Router)
- IP 주소를 기반으로 패킷을 최적 경로로 전달
- 서로 다른 네트워크를 연결
- NAT, 방화벽 기능 수행
L3 스위치
- 스위치 + 라우팅 기능
- 하드웨어 기반으로 빠른 처리
로드밸런서 (Load Balancer)
L4 로드밸런서
- IP 주소 + 포트 번호 기반 분산
- TCP/UDP 계층에서 동작
- 빠르고 효율적
L7 로드밸런서
- 애플리케이션 데이터 (URL, 헤더, 쿠키) 기반 분산
- HTTP/HTTPS 계층에서 동작
- 더 세밀한 제어 가능 (예: /api는 서버A, /static은 서버B)
4. IP 주소
IPv4 vs IPv6
| 구분 | IPv4 | IPv6 |
|---|---|---|
| 주소 길이 | 32비트 | 128비트 |
| 표기법 | 192.168.0.1 | 2001:0db8:85a3::8a2e:0370:7334 |
| 주소 개수 | 약 43억 개 | 거의 무한대 |
| 헤더 크기 | 가변 (20~60 bytes) | 고정 (40 bytes) |
| NAT 필요 | 필요 | 불필요 |
클래스 기반 주소 체계
| 클래스 | 범위 | 용도 |
|---|---|---|
| A | 0.0.0.0 ~ 127.255.255.255 | 대규모 네트워크 |
| B | 128.0.0.0 ~ 191.255.255.255 | 중규모 네트워크 |
| C | 192.0.0.0 ~ 223.255.255.255 | 소규모 네트워크 |
| D | 224.0.0.0 ~ 239.255.255.255 | 멀티캐스트 |
| E | 240.0.0.0 ~ 255.255.255.255 | 예약됨 |
CIDR과 서브넷 마스크
CIDR (Classless Inter-Domain Routing)
클래스 없이 유연하게 IP 대역을 나누는 방식입니다.
192.168.1.0/24
├── 네트워크 부분: 192.168.1 (24비트)
└── 호스트 부분: 0~255 (8비트) → 256개 주소
서브넷 마스크
/24 = 255.255.255.0 → 256개 주소 (254개 사용 가능)
/25 = 255.255.255.128 → 128개 주소
/16 = 255.255.0.0 → 65,536개 주소
공인 IP vs 사설 IP
| 구분 | 공인 IP | 사설 IP |
|---|---|---|
| 범위 | ISP에서 할당 | 내부 네트워크용 |
| 인터넷 접속 | 직접 가능 | NAT 필요 |
| 고유성 | 전 세계 유일 | 네트워크 내에서만 유일 |
사설 IP 대역
- 10.0.0.0/8: 10.0.0.0 ~ 10.255.255.255
- 172.16.0.0/12: 172.16.0.0 ~ 172.31.255.255
- 192.168.0.0/16: 192.168.0.0 ~ 192.168.255.255
NAT (Network Address Translation)
사설 IP를 공인 IP로 변환하여 인터넷에 접속하게 해주는 기술입니다.
[내부 네트워크] [라우터/NAT] [인터넷]
192.168.1.10 ─────────→ 공인 IP 203.0.113.1 ─────→ 외부 서버
192.168.1.20 ─────────→ (포트로 구분)
- 장점: IP 주소 절약, 내부 네트워크 보호
- 단점: End-to-End 연결 어려움, P2P 제한
DHCP (Dynamic Host Configuration Protocol)
IP 주소를 자동으로 할당해주는 프로토콜입니다.
1. DISCOVER: 클라이언트가 DHCP 서버 탐색
2. OFFER: 서버가 사용 가능한 IP 제안
3. REQUEST: 클라이언트가 IP 요청
4. ACK: 서버가 IP 할당 확인
5. HTTP
HTTP 버전별 특징
| 버전 | 특징 |
|---|---|
| HTTP/1.0 | 연결당 하나의 요청/응답, 매번 연결 수립 |
| HTTP/1.1 | Keep-Alive (지속 연결), 파이프라이닝 |
| HTTP/2 | 멀티플렉싱, 헤더 압축, 서버 푸시, 바이너리 프로토콜 |
| HTTP/3 | QUIC 기반 (UDP), 0-RTT 연결, 향상된 멀티플렉싱 |
HTTP 메서드
| 메서드 | 설명 | 멱등성 | 안전 |
|---|---|---|---|
| GET | 리소스 조회 | O | O |
| POST | 리소스 생성 | X | X |
| PUT | 리소스 전체 수정 | O | X |
| PATCH | 리소스 부분 수정 | X | X |
| DELETE | 리소스 삭제 | O | X |
| HEAD | 헤더만 조회 | O | O |
| OPTIONS | 지원 메서드 확인 | O | O |
HTTP 상태 코드
| 범위 | 의미 | 주요 코드 |
|---|---|---|
| 1xx | 정보 | 100 Continue, 101 Switching Protocols |
| 2xx | 성공 | 200 OK, 201 Created, 204 No Content |
| 3xx | 리다이렉션 | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | 클라이언트 오류 | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found |
| 5xx | 서버 오류 | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
HTTP 메시지 구조
HTTP 메시지는 애플리케이션 계층의 데이터입니다. TCP/IP는 이 메시지를 그냥 바이트 덩어리로 운반할 뿐, 내용을 해석하지 않습니다.
| 구분 | 역할 |
|---|---|
| HTTP 메시지 | 받는 쪽 애플리케이션(웹 서버, 브라우저)이 "무슨 요청인지" 해석하기 위한 구조 |
| 세그먼트/패킷/프레임 | 그 메시지를 운반하기 위한 포장 (TCP/IP는 내용을 모름) |
즉, HTTP 메시지 구조는 서버가 "이게 GET인지 POST인지", "JSON인지 HTML인지" 알기 위해 필요합니다.
요청 (Request)
GET /api/users HTTP/1.1 ← 요청 라인 (메서드, URL, 버전)
Host: example.com ← 헤더
Content-Type: application/json
Authorization: Bearer token123
{"name": "John"} ← 바디 (선택)
요청 구성 요소:
| 구성 요소 | 설명 | 예시 |
|---|---|---|
| 요청 라인 | 메서드 + URL + HTTP 버전 | GET /api/users HTTP/1.1 |
| Host | 요청 대상 서버 | example.com |
| Content-Type | 바디의 데이터 형식 | application/json |
| Authorization | 인증 정보 | Bearer token123 |
| Accept | 클라이언트가 원하는 응답 형식 | application/json |
| Cookie | 저장된 쿠키 전송 | sessionId=abc123 |
| User-Agent | 클라이언트 정보 | Mozilla/5.0... |
| Origin | 요청 출처 (CORS) | https://example.com |
응답 (Response)
HTTP/1.1 200 OK ← 상태 라인 (버전, 상태코드, 상태메시지)
Content-Type: application/json ← 헤더
Content-Length: 45
Cache-Control: no-cache
{"id": 1, "name": "John"} ← 바디
응답 구성 요소:
| 구성 요소 | 설명 | 예시 |
|---|---|---|
| 상태 라인 | HTTP 버전 + 상태코드 + 메시지 | HTTP/1.1 200 OK |
| Content-Type | 바디의 데이터 형식 | application/json |
| Content-Length | 바디 크기 (바이트) | 45 |
| Cache-Control | 캐시 정책 | no-cache, max-age=3600 |
| Set-Cookie | 쿠키 설정 | sessionId=abc; HttpOnly |
| Location | 리다이렉트 URL (3xx) | https://new-url.com |
| Access-Control-Allow-Origin | CORS 허용 출처 | * 또는 특정 출처 |
| ETag | 리소스 버전 식별자 | "abc123" |
HTTP 응답 바디 형태
응답 바디는 Content-Type 헤더에 따라 다양한 형식을 가집니다.
| Content-Type | 형태 | 예시 |
|---|---|---|
application/json | JSON | {"key": "value"} |
text/html | HTML | <html><body>...</body></html> |
text/plain | 일반 텍스트 | Hello World |
application/xml | XML | <root><item>...</item></root> |
application/octet-stream | 바이너리 | 파일 다운로드 |
multipart/form-data | 멀티파트 | 파일 업로드 |
Chunked Transfer Encoding
큰 응답을 청크 단위로 나누어 전송합니다.
HTTP/1.1 200 OK
Transfer-Encoding: chunked
7\r\n
Hello, \r\n
6\r\n
World!\r\n
0\r\n
\r\n
- 전체 크기를 미리 알 수 없을 때 사용
- 스트리밍 응답에 활용
6. 실시간 통신
통신 방식 비교
| 방식 | 설명 | 장점 | 단점 |
|---|---|---|---|
| Polling | 일정 주기로 서버에 요청 | 구현 간단 | 불필요한 요청, 지연 |
| Long Polling | 응답까지 연결 유지 | 실시간에 가까움 | 서버 부하 |
| WebSocket | 양방향 지속 연결 | 완전한 실시간 | 구현 복잡 |
| SSE | 서버→클라이언트 단방향 | HTTP 기반, 간단 | 단방향만 가능 |
WebSocket
HTTP Upgrade를 통해 양방향 전이중 통신을 수립합니다.
// 클라이언트
const ws = new WebSocket("wss://example.com/socket");
ws.onopen = () => {
ws.send("Hello Server");
};
ws.onmessage = event => {
console.log("받은 메시지:", event.data);
};
ws.onclose = () => {
console.log("연결 종료");
};Server-Sent Events (SSE)
서버에서 클라이언트로 단방향 스트리밍을 제공합니다.
// 클라이언트
const eventSource = new EventSource("/api/stream");
eventSource.onmessage = event => {
console.log("받은 데이터:", event.data);
};
eventSource.onerror = () => {
eventSource.close();
};스트리밍 연결 관리
서버에서 연결 종료하는 방법
1. HTTP 헤더 사용
HTTP/1.1 200 OK
Connection: close
Content-Type: text/plain
데이터...
서버가 Connection: close를 응답에 포함하면, 응답 완료 후 TCP FIN을 전송합니다. 클라이언트는 FIN을 받으면 연결이 종료되었음을 인식합니다.
[동작 과정]
1. 서버: Connection: close 헤더 포함하여 응답
2. 서버: 응답 완료 후 TCP FIN 전송
3. 클라이언트: FIN 수신 → 소켓이 EOF 상태
4. 클라이언트: 'end' 또는 'close' 이벤트 발생
2. 스트림 종료 신호 전송
// SSE에서 서버 측 (Node.js 예시)
res.write("event: close\n");
res.write("data: stream ended\n\n");
res.end();3. 타임아웃 설정
// 서버 측
const timeout = setTimeout(() => {
response.end();
}, 30000); // 30초 후 종료4. WebSocket 서버에서 종료
// Node.js ws 라이브러리
ws.close(1000, "Normal closure");
// 클로즈 코드
// 1000: 정상 종료
// 1001: Going Away (서버 종료)
// 1008: Policy Violation클라이언트에서 연결 종료하는 방법
1. AbortController (Fetch API)
const controller = new AbortController();
fetch("/api/stream", { signal: controller.signal })
.then(response => response.body.getReader())
.then(reader => {
// 스트림 읽기
});
// 연결 종료
controller.abort();2. EventSource 종료
eventSource.close();3. WebSocket 종료
ws.close();참고 자료
- MDN Web Docs - HTTP
- TCP/IP 완벽 가이드
- RFC 793 (TCP), RFC 2616 (HTTP/1.1), RFC 7540 (HTTP/2)