Network Programming/Transport Layer
[Transport Layer] Introduction
dh_0e
2025. 6. 2. 02:12
Transport Layer (전송 계층)
- Network Layer(네트워크 계층)와 Application Layer(응용 계층) 사이에 위치함
- 응용 계층에 서비스를 제공하고, 네트워크 계층으로부터 서비스를 받음
- IP datagram이 Host에 도달하면 다음 프로세스를 처리하는 layer로 양쪽 Host에 위치하여 IP datagram을 상위 계층에 전달
Process
- 응용 계층의 개체, 즉 실행 중인 프로그램
- 전송 계층의 서비스를 사용하여 통신함
Host-to-host communication vs Process-to-process communication
- 네트워크 계층은 컴퓨터 단위의 통신(host-to-host)을 담당 (NIC(Network Interface Card) 까지)
- 이 메시지는 특정 프로세스에 전달되어야 하므로 전송계층은 메시지를 정확한 응용 프로세스에 전달하는 책임이 있음
Transport-Layer Services
- 일단 UDP는 error control 없음
- 전송 계층의 목적은 응용 프로세스 간 통신을 가능하게 하는 것
- 이를 위해 포트 번호를 사용함
- IP 주소: 목적지 host를 식별
- 포트 번호: 해당 호스트 내 응용 프로세스를 식별
- 즉, IP 주소+포트 번호 조합이 특정 응용 프로그램(프로세스)을 지정함
Process-to-Process Communication
ICANN Ranges
국제 인터넷 주소 관리 기구(ICANN)는 포트 번호를 3가지 범위로 나눔
- Well-known (0~1023): 국제적으로 할당된 특정 프로세스
- 운영체제나 시스템 서비스용으로 ICANN이 지정 및 통제함
- 별도의 설정 없이 연결 가능
- ex) SSH, e-mail ...
- Registered Ports (1024~49151): ICANN에 사용료를 내고 등록해놓은 프로세스
- 일반 애플리케이션용으로 ICANN의 직접 통제는 없지만, 등록 가능함
- 충돌 방지를 위해 등록하면 해당 포트를 예약할 수 있음
>> 포트가 유일하므로 중복이 방지됨 - ex) Docker, MySQL
- Dynamic(or private) (49152~65535): 자유롭게 할당 가능한 임시 통신용 포트
- 사용자가 임의로 사용 가능하며 일반적으로 클라이언트 측에서 동적으로 할당됨
NAT 환경에서는 하나의 공인 IP를 여러 내부 프로세스가 공유하더라도, 포트 번호를 사용하면 개별 프로세스를 구분하여 통신할 수 있음
Socket Address
- IP 주소 + 포트 번호 = Socket address
- 이 조합을 통해 특정 호스트의 특정 프로세스를 정확히 식별 가능
Multiplexing and Demultiplexing
- Multiplexing: 여러 응용 프로세스 >> 하나의 전송 계층으로 데이터 전달
- ex) 브라우저, 메신저, 유튜브가 동시에 동작해도, 하나의 전송 계층(TCP/UDP)은 이를 모두 처리함
- Demultiplexing: 하나의 전송 계층 >> 여러 응용 프로세스로 데이터 분배
- 응용 계층(브라우저, 메신저 등) 개발자는 TCP/UDP, IP 등 하위 계층을 직접 다루지 않음
- 하위 계층은 OS가 처리함 but IoT 개발자는 하위 계층까지 조작함
- Linux에서는 소켓이라는 인터페이스를 통해 OS가 처리하며, 일반 개발자는 이 소켓만 다루면 됨
Flow control
Pushing vs Pulling
- 일종의 buffer overflow 예방
- Pushing: 생상자가 데이터를 생성하자마자 소비자에게 자동 전송됨
>> 수신자가 준비 안 돼 있어도 일단 보냄 - Pulling: 소비자가 데이터를 요청한 후에야 전송됨
- >> 수신자가 먼저 준비됨
Flow Control at T-L
흐름 제어 요청 (ex: 버퍼가 꽉 찼다)
- 송신 전송 계층 <> 송신 애플리케이션 계층
- 애플리케이션 계층이 너무 빨리 데이터를 생성할 경우 전송 계층이 감당 못할 수 있음
- 수신 전송 계층 <> 송신 전송 계층
- 네트워크 속도나 수신 측 버퍼가 부족할 경우, 송신 속도를 제어할 필요가 있음
즉, 전송 계층은 위(앱 계층)와 아래(수신 전송 계층) 모두와의 속도 차이를 고려해야 함
Error Control
에러 제어의 목적
- 손상된 패킷 감지 및 제거
- 손실된/제거된 패킷 추적 및 재전송
- 중복 패킷 식별 및 제거
- Out-of-order(순서가 어긋난) 패킷 버퍼에 임시 저장 / 누락된 패킷 도착 시 조립
에러 제어는 오직 전송 계층끼리 수행됨
- 송신 전송 계층, 수신 전송 계층 간의 통신에서만 이루어짐
- 애플리케이션 계층이나 네트워크 계층은 관여하지 않음
- 침묵도 error control의 일종임
Sequence Numbers
- 패킷들의 순서(index)
- 송신 측: 어떤 패킷을 재전송해야 하는지 알기 위해 각 패킷에 번호 부여
- 수신 측: 어떤 패킷이 중복인지, 순서가 틀렸는지 판단하기 위해 시퀀스 번호 사용
- 오류 복구뿐 아니라 순서 제어에도 핵심이 되는 정보
Acknowledgment
- 수신 측에서 수신 성공 시 ACK 메시지를 송신자에게 보냄
- 실패 시 NAK 보내는데 TCP/UDP는 ACK 밖에 없음
- 송신 측은 ACK를 일정 시간 안에 못 받으면 해당 패킷이 손실된 것으로 판단하고 재전송
Congestion Control
- 네트워크로 보내는 패킷의 양이 네트워크 용량(bps)을 초과(LOSS)할 때 발생
- 너무 많은 패킷이 몰리면 지연이 길어지고, 패킷 손실 증가
Open-Loop Congestion control
- 혼잡이 발생하기 전에 미리 대처하는 방식
- Retransmission Policy: 재전송 전력
- 너무 자주 재전송하지 않도록 제한
- Window Policy: 윈도우 크기 설정 전략
- 전송 윈도우의 크기로 전송 속도 조절
- Acknowledgment Policy: ACK 방식 조정
- ACK 빈도 조절로 혼잡 감소
Closed-Loop Congestion control
- Network 상태를 관찰하다 혼잡이 발생한 후 전송 속도를 dynamic 하게 조절하여 혼잡도 조절
- ex) 패킷 손실이 많아지면, 혼잡으로 판단하고 윈도우 크기 줄임
Connectionless Service
- 각 패킷이 서로 독립적(independency)으로 전송됨
- 패킷 간에 관계가 없으며 순서 보장도 안 되고 연결도 없음
- 응용 프로그램은 메시지를 여러 조각으로 나눠 전송 계층에 직접 전달
- 빠르고 간단하지만 신뢰성 낮으며 오버헤드 작음
- Out-of-order(bound)는 app layer가 담당 (패킷 순서에 따라 어찌할 건지)
- ex) UDP (User Datagram Protocol)
Connection-Oriented Service
- 데이터를 전송하기 전에 client와 server가 connection을 먼저 establish 하는 방식
- 순서 보장, 오류 제어, 흐름 제어, 혼잡 제어 등 부가 기능 제공
- 데이터 전송이 끝나면, 양측은 명시적으로 연결을 종료함
- Connectionless에 비해 절대적으로 우월한 건 아님 (상황에 맞게 사용)
- 신뢰성이 있으며 추가 작업과 오버헤드 존재
- ex) TCP (Transmission Control Protocol)
구분 | 비연결형 (UDP 등) | 연결형 (TCP 등) |
연결 설정 | 없음 | 있음 (handshake) |
순서 보장 | X | O |
오류 복구 | X | O |
속도 | 상대적으로 빠름 | 상대적으로 느림 |
오버헤드 | 작음 | 큼 |
Stop-and-wait Protocol
- 전송 계층에서 가장 단순한 신뢰성 있는 전송 방식
- 송신자는 한 번에 하나의 패킷만 전송
- 전송 후 수신자로부터 ACK(확인 응답)을 기다림
- ACK가 오면 다음 패킷 전송
or ACK가 안 오면(타이머 만료) 패킷 다시 전송
- flow control, error control을 모두 포함
- 수신자와 송신자 모두 사이즈 1의 sliding window 사용
- 수신자의 침묵은 "문제가 생김"(패킷 손실 or 손상)으로 간주
Sequence Numbers
- 송신자는 각 데이터 프레임에 시퀀스 번호를 붙임
- 수신자는 ACK를 보낼 때, 수신한 프레임의 번호를 기반으로 보냄
- Stop-and-Wait에서는 0과 1만 번갈아가면서 보냄
- window size = 1
- sequence size(length) = 2 (0 or 1)
- 같은 패킷이 여러 번 수신되었을 때, 시퀀스 번호를 기준으로 중복 여부를 판단
Stop-and-Wait는 채널이 굵고 길 수록 비효율적임
Thick Channel: 대역폭이 큰 채널 >> 한 번에 데이터를 더 많이 보낼 수 있음
Long Channel: 왕복 지연 시간(Round Trip Time)이 긴 채널
채널은 물통인데, Stop-and-Wait은 물 한 컵만 들고 가서 기다리는 꼴
Go-Back-N Protocol (GBN)
- 여러 패킷을 ACK를 기다리지 않고 연속해서 보낼 수 있지만 수신자는 단 한 개의 패킷만 버퍼링 가능한 방법
- 송신 측은 보낸 패킷들을 보관, ACK가 올 때까지 유지
- 채널에는 여러 개의 데이터 패킷과 ACK가 동시에 존재 가능
- 수신자가 단 하나의 패킷만 버퍼링이 가능해서out-of-order 된 패킷은 모두 폐기
Sequence Numbers
- 시퀀스 번호는 $2^m$ 단위로 m은 시퀀스 필드 비트의 크기를 의미
- ex) 시퀀스 필드 비트가 3비트면 번호 범위는 0~7
- window size와 함께 고려
- window size 크기는 시퀀스 번호 공간 내에서 중복 없이 구분 가능할 만큼만 설정해야 함
- ex) 시퀀스 번호 범위가 $2^m$이면 최대 윈도우 크기는 $2^m-1$
Acknowledgment Numbers
- GBN의 ACK는 cumulative(누적) 방식 사용
- 누락된 ACK가 있어도 이후 번호의 ACK 하나만 도착하면 앞에 것들까지 모두 확인됨
- ex) ackNo=7을 받으면 0~6까지는 무사히 받았고, 7번 패킷을 기다린다는 뜻
Send Window
- 현재 보낼 수 있거나, 보냈지만 아직 ACK 못 받은 패킷들의 시퀀스 번호 범위
- 윈도우의 크기만큼 연속 전송이 가능하며 ACK가 오지 않은 패킷들은 윈도우 안에 그대로 남아 있음
- 수신자가 누적 ACK만 보내므로 한 칸의 여유가 있어야 중복 구분 가능 >> maximum window size = $2^m-1$
- 밑에서 중복 구분 다시 설명
- Region 1 (left of the window): 이미 끝난 통신
- 이미 ACK를 받았고, 전송 완료된 패킷들
- 더 이상 관리할 필요 없음
- Region 2 (colored): 보냈는데 ACK 못 받음
- 전송 완료 + 아직 응답 대기 중
- 윈도우에서 보관 중인 상태로 타이머가 동작 중
- Region 3 (white in the figure): 보낼 수 있는데 요청이 없음
- 시퀀스 번호로는 윈도우 안에 있지만, 아직 애플리케이션 계층으로부터 전송할 데이터 자체를 못 받음
- 대기 중
- Region 4 (right of the window): 아직 보낼 수 없음
- 현재 시점에서 보낼 수 없는 시퀀스 번호 범위
- 윈도우가 슬라이드하면 이 영역이 앞으로 이동해서 사용 가능해짐
윈도우 포인터 변수
변수 | 의미 |
Sf (Send First) | 아직 ACK 안 받은 가장 처음 시퀀스 번호 |
Sn (Send Next) | 다음에 보낼 시퀀스 번호 |
Ssize | 윈도우 크기 (윈도우가 커질수록 한 번에 보낼 수 있는 패킷 수 증가) |
Receive Window
- GBN에서 수신자의 window size는 1로, 수신자는 단 하나의 시퀀스 번호만 기대함
- 정확히 그 번호가 아니면 무조건 버림
- ex) 기대 시퀀스 번호가 4인데 5가 오면 바로 폐기
- 기대하던 시퀀스 번호의 패킷이 정확히 도착하면 윈도우가 다음 번호로 슬라이드
- Rn(Receive Next)만 기다림
Reason of (Send window size < $2^m$)
- 4개의 패킷 전송
- ACK 모두 손실
- Time-out으로 재전송
- 수신자 입장에선 다음 0에 해당하는 패킷이 제대로 도착
but 송신자 입장에선 재전송한 거임
- 4개의 패킷 전송
- 모든 ACK 손실
- Time-out으로 패킷 재전송
- 수신자는 3 패킷을 기다리기 때문에 0~2 재전송된 패킷은 사이클로 인식되어 중복으로 판단 >> 무시
Cumulative Acknowledgments
- ACK2가 손실되어도 ACK3을 받으면 누적 ACK이기 때문에 송신자가 '2까지 패킷들이 모두 잘 도착했구나'를 알 수 있음
- 덕분에 일부 ACK 손실이 생겨도 전체 전송 흐름이 멈추지 않음
- ACK1은 이미 받았고, 계속 같은 ACK1 만 도착
- 타이머 만료 후 패킷 1부터 다시 전송 (Go-Back and resend)
- 단순하지만 낭비가 많을 수 있음
Selective-Repeat (SR) Protocol
- 네트워크가 혼잡하면 패킷 손실이 많아지며 GBN은 하나라도 손실되면 뒤에 거 전부 다시 전송
- >> 손실이 많은 경우, 재전송 오버헤드가 커지고 혼잡이 더 심해지는 악순환 발생
- 손실된 패킷만 선택적으로 재전송
- 하나라도 손실되면 그것만 골라서 다시 보냄
- 나머지 도착한 패킷들은 보관해 뒀다가 나중에 순서 맞춰서 넘김
Two Windows
- Send window size가 더 작아짐!
- GBN: $2^m-1$
- SR: $2^{m-1}$
- Wsender = Wreceiver (Window Size)
- Receive window size와 Send window size가 같기 때문에 윈도우 크기만큼 out-of-order 패킷 저장 가능
- 수신자는 순서와 상관없이 패킷을 수신하면 버리지 않고 저장
- 정확한 순서로 도착한 패킷이 누적되었을 때 순서 맞춰서 상위 계층에 전달
- 그전까지는 버퍼에 보관만 하고 기다림
- ex) 5를 기대하는 중에 6, 7이 도착했을 때 >> 둘 다 보관
나중에 5 도착 >> 5부터 6, 7 순차적으로 함께 상위 계층에 전달
송신 윈도우 (Send window)
- 여러 패킷을 한 번에 전송 가능
- 각 패킷마다 개별 타이머, 개별 ACK 관리
- 정밀한 재전송이 가능하지만 패킷마다 타이머 관리가 필요하여 구현이 복잡함
- GBN에서는? 가장 처음 보낸 패킷(첫 패킷)에만 타이머 설정
- 만료되면 전체 윈도우 내 모든 패킷 재전송
- 구현은 간단하지만 오버헤드 큼
- 전송한 패킷은 ACK 받을 때까지 윈도우에 유지
- ACK 받으면 해당 시퀀스 번호 윈도우에서 제거
- 타이머 만료 >> 해당 패킷만 재전송
수신 윈도우 (Receiver Window)
- 윈도우 크기만큼 out-of-order 패킷을 저장 가능
- 받은 패킷은 버리지 않고 해당 시퀀스 번호에 저장
- 기대한 번호가 도착하면 순서대로 상위 계층에 전달 + 윈도우 슬라이딩
Acknowledgments
- GBN의 ACK = cumulative(누적) ACK
- SR의 ACK = 개별 ACK
항목 | Go Back N Protocol | Selective Repeat Protocol |
타이머 | 1개 (첫 패킷용) | 각 패킷마다 1개 |
ACK | 누적 ACK | 개별 ACK |
재전송 | 전체 재전송 | 필요한 패킷만 선택적 재전송 |
복잡도 | 낮음 | 높음 |
효율 | 낮음 | 높음 |
Reason of "S-R window size <= $2^{m-1}$"
- 시퀀스 번호 필드 크기: m = 2
- 시퀀스 번호 범위: 0~3 (4)
- Case a에선 중간에 ACK가 모두 손실돼도, 수신자는 시퀀스 번호 0을 중복이 아닌 새 패킷으로 착각하지 않음
- Case b에선 이미 받은 시퀀스 번호를 다음 사이클의 새 패킷으로 오해 >> 중복 구분 못함
Bidirectional Protocols: Piggybacking(어부바)
- 데이터와 ACK를 하나의 패킷으로 합쳐서 전송하는 기법
- 양방향 통신 상황에서의 일반 방식
- A > B로 데이터 보냄 - B는 ACK 보냄
- B > A로도 별도로 데이터 보냄 - A는 또 ACK 보냄
- 패킷 수가 많아짐, ACK도 전용 패킷으로 낭비됨
- Piggybacking 방식
- A가 B에게 데이터 보낼 때, 데이터 패킷에다가 B에서 도착한 패킷에 대한 ACK를 얹어서 같이 전송