개요
| 항목 | 내용 |
|---|---|
| TCP가 보장하는 것 | 순서 있는 바이트 스트림 (신뢰성, 순서) |
| TCP가 보장하지 않는 것 | send 단위 = 수신 recv 단위. 메시지(프레임) 경계 |
| 애플리케이션의 역할 | 스트림에서 한 메시지의 시작·끝을 규칙으로 정의 → 프레이밍(Framing) |
send를 여러 번 호출해도 수신 측은 한 번에 이어붙인 덩어리로 받을 수도, 임의로 쪼개서 받을 수도 있음. Nagle, 세그먼트 분할 등은 TCP 내부 동작.
1. 구분자 (Delimiter)
형태: 본문 뒤에 고정 바이트 시퀀스로 끝맺음.
[페이로드][구분자]
HTTP/1.1 예: 요청/응답 헤더는 \r\n\r\n 종료, 바디는 Content-Length 등으로 길이.
| 이점 | 구현 난이도 낮음 |
| 제약 | 본문에 구분자와 같은 바이트가 나오면 이스케이프·이스케이프 해제 규칙 필요 |
| 바이너리 | 구분자가 데이터 안에 자연스럽게 나타날 수 있어 비권장에 가까움 |
2. 길이 프리픽스 (Length-Prefix)
형태: 페이로드 길이를 헤더에 두고, 그다음에 N바이트를 본문으로 읽기.
[길이 필드(고정 비트/바이트)][N바이트 페이로드]
수신 절차 (예: 길이 4바이트)
- 길이 필드 N바이트(예: 4) 완전히 읽기
- N을 정수로 해석한 뒤, 그 횟수만큼 본문 읽기
페이로드에 어떤 바이트 패턴도 올 수 있음 — 경계는 길이 필드에만 의존.
확장: 타입(명령 코드) 1바이트 + 길이 4바이트 + 본문 등, 헤더를 고정 길이로 잡는 패턴.
3. 엔디안 (길이·정수 필드)
정수 1000 (0x000003E8)의 바이트 나열:
| 순서 | 예시(16진) | |
|---|---|---|
| Big Endian | 상위 바이트 선행 | 00 00 03 E8 |
| Little Endian | 하위 바이트 선행 | E8 03 00 00 |
- 대부분의 일반 PC·모바일 CPU(ARM, x86): Little Endian이 기본.
- IETF/RFC 맥락의 "네트워크 바이트 순서": Big Endian (RFC 1700 등에서 Network Byte Order로 통용).
중요: 송수신 코드에서 UInt32를 그냥 메모리에 붙이면(플랫폼 엔디안) 상호운용 시 길이 값 깨짐. Swift 예시는 bigEndian / init(bigEndian:)로 명시적 변환.
// 송신: 로컬 정수 → 네트워크(빅엔디안) 바이트
var length = UInt32(payload.count).bigEndian
data.append(Data(bytes: &length, count: 4))
// 수신: 네트워크(빅엔디안) 바이트 → 로컬
let length = UInt32(bigEndian: data[0..<4].withUnsafeBytes {
$0.load(as: UInt32.self)
})(위 data[0..<4]는 길이 필드가 페이로드 앞 4바이트인 경우. 헤더에 타입 1 + 길이 4이면 data[1..<5]로 오프셋 조정.)
4. 수신: 부분 recv와 루프
길이 프리픽스 기준 최소 2단계: (1) 헤더 고정 길이, (2) length만큼 본문.
recv(n)은 한 번에 n바이트를 보장하지 않음. 부분 수신.
def recv_exact(sock, n):
data = b''
while len(data) < n:
chunk = sock.recv(n - len(data))
if not chunk:
raise ConnectionError("connection closed")
data += chunk
return data
# 예: type 1 + length 4
header = recv_exact(sock, 5)
msg_type = header[0]
length = int.from_bytes(header[1:5], 'big')
payload = recv_exact(sock, length)5. 방식 비교
| Delimiter | Length-Prefix | |
|---|---|---|
| 구현 | 단순 | 고정 헤더 + recv_exact 수준 |
| 바이너리 페이로드 | 이스케이프 부담 | 길이만 맞으면 무방 |
| 예 | HTTP/1.1 헤어 종료, 일부 텍스트 프로토콜 | gRPC(상위), 커스텀 바이너리, 게임/임베디드 |
용어
- Framing: TCP 스트림 위에 애플리케이션이 정의한 메시지 경계 규칙.
- Nagle: 작은 전송을 묶는 TCP 옵션.
send호출 횟수와 TCP 세그먼트 1:1이 아님. - Network Byte Order: 프로토콜에서 쓰는 빅엔디안 정수 표기.
- Length-Prefix Framing: 앞에 길이, 뒤에 N바이트 본문.