2.4전송 계층
오류 없이 데이터를 전달하는 단계
TL;DR
추억의 쪽지 시험
25. 전송 계층의 역할
전송 계층은 기본적으로 아래와 같은 역할을 수행한다:
- 오류를 점검해 종단 간(end-to-end) 데이터를 신뢰성 있게 전달
- 컴퓨터가 제대로 데이터를 받았을 경우, 어떤 애플리케이션으로 전달할지 포트 번호로 식별하여 여러 통신을 동시에 처리
25-1. 혼잡 제어
혼잡 제어(Congestion Control)는 네트워크로 들어가는 정보량을 조절하여 네트워크가 혼잡해지지 않게 조절하는 방법이다.
송신자가 우선 하나의 데이터를 보내고, 수신자로부터 ACK를 받으면 전송량을 2배씩 증가시킨다. 그러다가 Time Out(프로그램이 특정한 시간 내에 성공적으로 수행되지 않아 진행이 중단)이 발생하면, 여러 개 보냈던 데이터를 줄여 보낸다. 또는, 동일한 ACK를 여러번 받을 때도 네트워크가 데이터를 실어 나르느라 바빠 밀린 것이므로 데이터를 줄여서 보낸다.
이후 정상적인 ACK를 받게 되면 다시 데이터를 배수로 전송함으로 데이터 전송량을 늘린다.
25-2. 흐름 제어
흐름 제어는 앞서 데이터 링크 계층에서 살펴봤던 Stop & Wait 방식과 동일하게 진행된다. 송신자가 하나의 데이터를 전송한 후 다음 데이터를 전송하기 전에 확인 응답을 기다린다. ACK를 받은 후에야 다음 데이터를 보낸다.
25-3. 오류 제어
오류 제어 역시 데이터 링크 계층과 같은 목적이나, 방법은 달라서 확인 응답과 시간 초과 방법을 사용한다.
- 확인 응답: 수신자 측으로부터 ACK를 못 받으면 오류로 판단
- 시간 초과: 특정 시간 내에 ACK가 없으면 세그먼트에 오류가 있다고 판단
- 검사합(Checksum): 전송 중 데이터가 깨졌는지 검사할 수 있는 수단
이렇게 오류가 발견되면 데이터를 재전송해야 하는데, 재전송은 아래와 같은 상황에 필요하다.
- 데이터가 중간에 손실
- 데이터 순서가 바뀜
- 데이터가 훼손
26. 3방향 핸드셰이크
데이터를 전달하는 목적에 따라 통신은 연결형과 비연결형 통신으로 나뉜다.
- 연결형: 데이터를 정확하게 전달하는 것을 목표로 한다. TCP 프로토콜을 사용한다.
- 비연결형: 데이터를 효율적으로 보내는 것을 목표로 한다. UDP 프로토콜을 사용한다.
TCP 프로토콜은 3방향 핸드셰이크(3 Way Handshake) 방법으로 통신을 시작한다. 이는 데이터를 정확하게 전달하는 것을 목표로 하는 것으로, 상대방이 내 신호를 받을 수 있는 상태인지 확인하고 데이터를 전송하는 방식이다. 즉, 3방향 핸드셰이크는 TCP 통신을 하는 장치끼리 서로 통신할 준비가 되었는지 확인하는 과정이다.
- 먼저 송신자는 수신자에게 SYN(Synchronize Sequence Number)라는 임의의 숫자를 보낸다. "안녕, 내 말 잘 들려?" 같은 의미다.
- 수신자는 이에 대한 ACK라는 "응, 잘 들려" 응답과, 송신자에게도 "너도 내 말 잘 들려?"라는 의미로 SYN을 보낸다. ACK는 받은 SYN에 1이 더해진 숫자이고, 보내는 SYN은 임의의 숫자다.
- 마지막으로 송신자가 "응, 나도 잘 들려"라는 응답의 ACK를 보낸다. 이는 수신자에게 받은 SYN에 1을 더한 숫자다.

이 과정을 통해 통신을 위한 연결이 수립되고, 송신자와 수신자 양쪽 모두 데이터를 전송할 준비가 되었다는 것이 보장된다.
네트워크 패킷 분석을 통해 본문 하단에서 직접 3-Way Handshake를 캡처해 보았다.
27. TCP의 구조
전송 계층의 헤더 정보에는 포트 번호를 포함해 여러가지 정보들이 붙는다.

27-1. 포트 번호
전송 계층은 어떤 애플리케이션과 통신하는지 정의하는 곳이고, 이 기능을 하는 것이 포트 번호다. 컴퓨터의 주소가 IP 주소라면, 프로그램의 주소가 포트 번호다.
포트 번호는 총 65,536개가 존재하며, 다음과 같이 나뉘어져 있다.
- 0~1023번: Well-known port(잘 알려진 포트)로, 특정한 쓰임을 위해 사용되는 포트
- 1024~49151번: Registered port(사전 등록된 포트): 기관이나 기업들이 사용하는 포트
- 49152~65535번: Dynamic port(다이내믹 포트)로, 일반 사용자들이 자유롭게 사용하는 포트
Well-known port에는 아래와 같은 것들이 있다.
| 포트 | 프로토콜 | 용도 |
|---|---|---|
| 20 | FTP | 데이터 전송 |
| 25 | SMTP | 이메일 전송 |
| 53 | DNS | IP 주소와 도메인 이름 변환 |
| 80 | HTTP | 웹 페이지 전송 |
| 123 | NTP | 시간 동기화 |
| 443 | HTTPS | 암호화된 웹 페이지 전송 |
예를 들어, 192.168.2.34라는 IP를 쓰는 수신자에게 이메일을 전달한다면, 전달할 때 헤더에 25번 포트가 붙는다. 192.168.2.34를 쓰는 수신자는 25번 포트를 통해 이메일을 열어 확인한다.
27-2. 일련번호와 확인 응답 번호
전송 계층의 헤더엔 일련번호와 확인 응답 번호도 붙는다.
일련번호는 송신자가 수신자에게 보내려는 데이터가 몇 번째인지 알려주고, 반대로 확인 응답 번호는 수신자가 몇 번째 데이터를 받았는지 송신자에게 알려준다.
예를 들어, 1500 바이트의 데이터를 보내려는데, 한 번에 보낼 수 있는 데이터(이를 패킷이라고 한다)가 500 바이트인 상황을 가정하자. 이러면 모든 데이터를 보내려면 500씩 3번을 보내야하는데, 이 3번의 패킷에 각각 일련번호가 1, 501, 1001(각각 500번째 바이트 뒤이므로) 식으로 붙는다.
이 경우 확인 응답 번호는 501, 1001, 1501이 쓰인다. 즉, 500 바이트의 데이터를 받았으므로 그 다음 데이터는 501부터 보내달라는 의미이고, 이후는 1001을 보낸다. 마지막에는 1501을 보내지만 송신자는 더 이상 보낼 패킷이 없다.
이렇게 일련번호와 확인 응답 번호를 사용하면 수신한 데이터가 순서가 맞는지, 오류는 없는지를 확인할 수 있다.
27-3. 윈도우 크기
수신자가 받을 수 있는 데이터의 양은 적은데, 송신자가 그걸 고려하지 않고 많은 양의 데이터를 보낸다면 송신자 입장에선 데이터를 모두 보냈다고 생각하지만 수신자는 일부 데이터를 받지 못했을 것이다.
따라서, 송신자는 수신자가 얼마나 큰 데이터를 받을 수 있는지 확인해야하는데, 수신자가 한 번에 받아줄 수 있다고 광고(advertise)하는 데이터 양을 윈도우 크기(window size)라고 한다. 즉, 윈도우 크기는 송신자가 ACK 없이 연속해서 보낼 수 있는 데이터의 최대 크기이다.
수신자의 윈도우 크기는 3방향 핸드셰이크 때, SYN과 ACK 외에도 Window_Size라는 정보를 주고 받음으로 알게 된다. 이렇게 3방향 핸드셰이크 때 윈도우 크기를 파악함으로 수신자가 받을 수 있을 만큼 데이터를 한번에 보내 보다 효율적인 통신이 가능해진다.
27-4. 코드 비트
코드 비트에는 아래와 같은 정보들이 포함되는데, 모두 기본값이 0이고 활성화되면 1의 값을 가진다.
| 항목 | 뜻 |
|---|---|
| URG | 긴급 처리 데이터가 있음 |
| ACK | 확인 응답 번호가 유효함 |
| PSH | TCP가 받은 데이터를 상위 계층에 전달 |
| RST | 연결 재설정(비정상 상황에서 연결 강제 종료) |
| SYN | 연결을 초기화하기 위해 순서 번호 동기화 |
| FIN | 더 이상 보낼 데이터가 없음(데이터 송신 종료) |
예를 들어, 3방향 핸드셰이크에선 연결을 위해 SYN과 ACK가 사용되는데, 그러면 SYN과 ACK는 값이 0에서 1로 변화한다. 또, 연결이 종료될 때는 ACK와 FIN이 사용되는데, 이것들이 1로 변화한다.
28. UDP의 구조
TCP는 데이터를 세그먼트라는 단위로 쪼갠 후 순서를 부여하여 전송한다. 수신자 입장에선 세그먼트의 순서가 뒤바뀌는 일이 없도록 오류를 제어한다.
이렇듯 신뢰성 있는 통신을 기반으로 했던 것이 TCP라면, UDP(User Datagram Protocol)는 데이터를 수신자 측에서 오류 없이 받던, 그렇지 않던 상관없이 데이터를 보내기만 한다.
신뢰성을 보장하지 않지만, 그러기에 UDP는 데이터 전송 속도가 빠르다. 따라서 실시간 방송 등에선 UDP가 적합하다. 또, 브로드캐스트의 경우에도 프로토콜로 UDP가 사용된다.
UDP 프로토콜은 신뢰성에 대한 부분을 신경 쓰지 않기에 TCP에 비해 상당히 간단한 정보만 담은 헤더를 사용한다. 송/수신자의 포트 번호와 헤더 길이, 검사합(Checksum) 정도만 포함된다.
| 항목 | 설명 | 크기 |
|---|---|---|
| 송신자 포트 번호 | 데이터를 보낼 때 사용되는 애플리케이션 포트 번호 | 16비트 |
| 수신자 포트 번호 | 데이터를 받을 애플리케이션의 포트 번호 | 16비트 |
| 헤더 길이 | UDP 헤더와 데이터를 합한 총 길이 | 16비트 |
| 검사합 | 데이터 무결성 검사(오류 검사)용 | 16비트 |
29. 전송 계층에서 사용하는 로드 밸런서
수많은 동시 접속자가 있는 서비스는 여러 대의 서버를 둔다. 하지만 사용자들이 특정 서버 1대로 몰리는 현상이 발생하면 서버가 여러 대 있어도 소용이 없다.
이 때 필요한 것이 로드 밸런서(Load Balancer)로, 여러 대의 서버를 두고 사용자가 한쪽으로 몰리는 것을 분산시켜주는 장치다. 서버를 1대에서 여러 대로 늘리는 것을 스케일 아웃(Scale Out)이라고 하고, 부하를 분산시켜주는 작업을 로드 밸런싱(Load Balancing)이라고 한다.
전송 계층의 로드 밸런서는 우선 사용자들이 보내온 연결 요청을 받는다. 이후, 로드 밸런서는 서버로 연결을 분산해서 요청한다. 부하를 분산시키는 방법으로는 아래와 같은 방법들이 있다:
- 라운드 로빈(Round Robin): 각 서버별로 돌아가면서 연결을 처리한다.
- 가중 라운드 로빈(Weighted Round Robin): 돌아가면서 연결을 처리하는데, 일부 서버는 큰 트래픽을 몰아 받는다.
- 랜덤(Random): 무작위로 분배한다.
- 해시(Hash): 특정 클라이언트는 특정 서버에서만 처리한다.
또, 로드 밸런서는 포트 번호를 이용해 부하를 분산시킬 수도 있다. 예를 들어, 로드 밸런서 IP 주소로 접속하는 것 중 특정 포트를 사용하는 것은 해당 포트를 처리하는 서버로, 또 다른 포트를 사용하는 것은 그에 해당하는 서버로 전달하도록 설정할 수 있다.
🤠 개인 탐구
TCP 3-Way Handshake를 직접 보고 싶다는 생각이 들었다. 이 블로그에 접근을 요청하면 어떤 과정으로 페이지가 내 컴퓨터에 도달하는 걸까?
네트워크 통신 과정을 세밀하게 탐지하기 위해 Wireshark라는 소프트웨어를 다운 받았다. Wireshark는 네트워크 패킷 캡처 및 분석 소프트웨어로, 마치 통신망에 사는 상어처럼 (피 한 방울같이 작은 패킷도) 감시한다는 의미를 가졌다.
Wireshark를 설치한 후 맨 왼쪽 상단의 상어 지느러미(!) 아이콘을 눌러 실행해보면 짧은 순간에 엄청나게 많은 패킷이 지나가는 것을 볼 수 있다.

처음에 몇번 캡처를 시작하고 블로그에 접속하는 과정을 반복했으나, TCP 3-Way Handshake의 이력은 볼 수 없었다. 이유는 이미 연결이 성립된 상태였기 때문이었는데, 브라우저가 기존 TCP/TLS 연결을 재사용 했을 가능성이 높다(특히, HTTP/3(QUIC)으로 붙지 않았다는걸 이후에 알 수 있었으니 더더욱 이 가능성이 높다). 따라서 Wireshark에는 TLS에서 암호화된 데이터만 보였던 것이다.
따라서 브라우저를 모두 종료하고 Incognito 모드로 실행해, Wireshark로 캡처를 켜고 바로 www.sungyup.com 에 접속을 시도했다. 또, 내 블로그 서버의 IP 주소를 알기 위해 dig +short 명령어를 사용했다.
bashdig +short sungyup.com
dig는 DNS 서버(정확히는 재귀적으로 찾는 DNS Resolver)에게 질의해 도메인 → 레코드(IPv4 주소인 A, IPv6 주소인 AAAA, 별칭인 CNAME 등) 응답을 보여주는 도구로, Domain Information Groper의 약자다(Grope는 '더듬다'라는 단어다). +short는 dig의 출력 중 핵심 답만 짧게 보여주는 옵션이다. 결과는 아래와 같았다:
bash76.76.21.21
이 주소를 찾던 중, 전후 로그(특히 52~55에 명백히 찍혀있는 www.sungyup.com) 를 보면 확실히 이 블로그의 TCP 3-Way Handshake로 보이는 로그(아래 이미지의 56~58번)들을 발견했는데, Destination이 76.76.21.98로 약간 달랐다. 이는 로그를 보면 실제 브라우저 접속이 **www.**sungyup.com 으로 일어나, DNS 응답이 CNAME에서 여러 A 레코드를 내려줬고 그 중 하나인 76.76.21.98을 브라우저가 택했기 때문이다.
Source에 있는 1.1.1.1은 참고로 Cloudflare의 재귀 DNS Resolver이다.

이후에 보이는 과정은 TLS Handshake로, Client Hello라는 문구와 Protocol에 찍힌 TLSv1.3을 통해 방금 열린 TCP 연결 위에서 HTTPS를 위한 통신이 시작된 것을 확인할 수 있다. 이에 대해선 이후 네트워크 흐름 포스팅에서 보다 자세히 살펴본다.
요컨대, 브라우저에서 웹사이트에 리소스를 요청하면
- 우선 DNS 질의로 ip 주소를 얻고
- TCP 3-Way Handshake, 즉 TCP 헤더 기반으로 해당 ip 주소의 서버와 통신을 위한 연결을 수립하고
- 해당 연결 위에서 TLS Handshake로 보안 연결을 수립한 후
- HTTP 통신을 진행,
GET /index.html로 요청을 하고 응답을 받는다.