3.1 Transport-layer services
Transport 레이어는 서로 다른 호스트에서 동작하는 프로세스 간의 logical 한 통신을 제공한다.
Transport 프로토콜은 end system에서 동작합니다. (TCP, UDP.. )
- 송신 측 : 애플리케이션의 메세지를 segment로 쪼개서 network 레이어로 전달
- 수신 측 : segments를 메세지로 다시 조합하여 application 레이어로 전달
Network layer VS Transport layer
Network layer : 호스트 간 logical communication을 제공
Transport layer : 프로세스 간 logical communication을 제공 (네트워크 레이어에서 제공하는 서비스에 의존)
(비유를 하자면 여러 명이 사는 집에 우편서비스를 통해 편지를 배송하는 것은 network layer이고, 집에 도착한 편지를 사람마다 알맞게 나누어주는 것이 transport layer임)
Internet transport-layer protocols
- TCP : reliable, in-order delivery (congestion control, flow control, connection setup 제공)
- UDP : unreliable, unordered delivery (아무것도 제공하지 않음)
- delay나 bandwidth 에 대해서는 어떤 프로토콜도 보장해주지않음.
ex) TCP의 경우 IP 패킷이 drop되더라도 복구가 가능하지만, UDP의 경우 IP 패킷이 drop되면 UDP 패킷도 drop되어버림.
3.2 Multiplexing/Demultiplexing
Multiplexing (sender) : 여러 소켓으로부터 온 데이터들을 핸들링하고 transport 헤더를 추가함.
Demultiplexing (receiver) : 헤더정보를 사용하여 수신한 segment들을 올바른 소켓으로 전달함.
Demultiplexing의 동작방식
source port # (16bit) | destination port # (16bit) |
other header fields | |
application data (payload) |
(Transport layer segment 포맷을 나타냄)
- 호스트가 IP 데이터그램을 수신하는데, 각 데이터그램에는 source, destination IP주소가 들어있음.
- 각 데이터그램은 하나의 transport-layer segment를 전달하며, 각 세그먼트에는 source, destination port number가 들어있음.
- 호스트는 IP address와 Port number를 이용하여 segment를 올바른 소켓으로 전달함.
Connectionless demultiplexing (UDP)
호스트가 UDP segment를 받으면, 세그먼트 내의 destination port # 을 확인하고, 세그먼트를 해당 port #을 가진 소켓으로 넘겨줌.
UDP 소켓에 보낼 데이터그램을 생성할 때, 목적지의 IP address, port #만 있으면 됨.
같은 목적지 IP, port #를 갖는 데이터그램은 source IP/port#와 상관없이 같은 소켓으로 전달됨.
Connection-Oriented demultiplexing (TCP)
TCP 소켓은 source IP address/port #, destination IP address/port # 로 식별됨. (4개가 모두 다 있어야 demultiplexing이 가능함)
웹서버는 연결하는 클라이언트마다 서로다른 TCP 소켓들을 가지고있음. (non-persistent HTTP의 경우에는 각 request마다 다른 소켓을 가짐)
목적지 IP address/Port # 가 같더라도 source에 따라 다른 소켓으로 demux 될 수 있음.
3.3 Connectionless transport: UDP (User Datagram Protocol)
UDP 프로토콜은 전적으로 IP프로토콜이 제공하는 기능에 의존한다. 즉 네트워크레이어에서 제공하는 기능에 추가적으로 기능을 덧붙이지 않고 중개역할만 한다.
따라서 UDP 세그먼트는 손실될 수 있고, 각 UDP 세그먼트는 독립적으로 핸들링되기 때문에 애플리케이션 레이어에 out-of-order로 전달될 수 있다.
또한 TCP와 달리 sender와 receiver간에 handshaking을 수행하지 않는 connectionless protocol이다.
UDP는 congestion control을 제공하지 않기 때문에 전송속도를 통제하지 않고 원하는 만큼 빠르게 보낼 수 있다는 장점이 있다. (하지만 도착한다는 보장은 없음.)
이와같이 UDP 프로토콜은 하는 일이 없기 때문에 빠르다는 장점이 있으며, 조금의 손실은 상관없지만 빠른 속도가 필요한 스트리밍서비스 등에 이용될 수 있다.
UDP segment header
source port # | destination port # |
length (byte) | checksum |
application data (payload) |
UDP 는 커넥션을 생성하지 않기 때문에 송/수신자에 connection state를 저장할 필요가 없어 포맷이 단순하고, 헤더 사이즈가 작다. (8 bytes)
UDP가 하는 일
UDP는 아무것도 하는 일이 없어보이지만 2가지의 일이 있다.
1. checksum 을 이용한 error detection
2. multiplexing & demultiplexing
UDP Checksum
UDP 의 체크섬은 전송된 세그먼트에 있는 에러를 탐지하기 위해 존재한다.
sender : 헤더필드를 포함하여 segment를 2byte integer 단위로 분할한다. 그리고 1의 보수 덧셈으로 segment contents를 더하여 checksum을 생성한 후, UDP 체크섬 필드에 넣는다.
receiver : 수신한 세그먼트에서 계산한 체크섬과 체크섬 필드에 적혀있는 체크섬을 비교한다. 다르면 에러가 존재하는 것이다. (같으면 에러가 없는 것으로 판단하지만, 사실은 에러가 존재할 수 있음)
3.4 Principles of reliable data transfer
Network 레이어가 제공하는 unreliable channel을 transport layer가 reliable하게 만들어서 application 레이어에게 제공한다. (그림의 rdt : reliable data transfer, udt : unreliable data transfer)
순차적으로 reliable data transfer protocol의 sender/receiver side를 향상시켜나가면서 rdt를 알아보자.
state 가 이동하는 화살표에 적힌 의미는 다음과 같다. (상태변화를 일으킨 이벤트 / 상태변화시 수행할 액션)
rdt1.0: reliable transfer over a reliable channel
하위 채널이 완벽하게 reliable하다고 가정한다. (bit error나 packet loss가 전혀 없는 이상적인 채널)
- sender : rdt_send가 호출되면 패킷을 만들어서 그대로 udt_send를 호출함.
- receiver : rdt_rcv가 호출되면 데이터를 가져와 위쪽 레이어로 올려줌.
- underlying channel이 reliable하기 때문에 transport layer에서는 뭘 더 할 필요 없이 그냥 전달해주면 됨.
rdt2.0: channel with bit errors
하위 채널이 패킷에 있는 bit을 fip시킬 수도 있다고 가정한다.
이 경우 transport layer에서 bit error를 탐지하여 복구해줘야한다. (checksum을 이용하여 bit error 탐지)
- ACKs (acknowledgements) : 수신자가 송신자에게 패킷을 잘 받았다고 말해주는 것
- NAKs (negative acks) : 수신자가 송신자에게 패킷에 오류가 있다고 말해주는 것
송신자는 NAK 메세지를 받으면 패킷을 다시 전송함으로써 에러를 복구할 수 있다.
송신자의 경우 rdt_send가 호출되면 checksum을 계산하여 패킷을 생성한 후 해당 패킷을 udt_send로 보낸다.
그리고 수신자로부터 ACK 또는 NAK 메세지가 오기를 기다린다.
수신자로부터 패킷이 도착하였는데, 만약 NAK이라면 udt_send를 통해 패킷을 다시 보내고 다시 답장이 오기를 기다린다.
수신자로부터 온 답장이 ACK이라면 패킷을 송신할 수 있는 상태로 돌아가서 rdt_send 호출을 기다린다.
수신자의 경우 송신자로부터 패킷이 오기를 기다린다.
패킷이 도착했는데, 계산한 checksum과 패킷에 적힌 checksum이 다르다면 udt_send를 통해 NAK 메세지를 보낸다.
체크섬이 동일하다면 패킷에서 데이터를 꺼내어 애플리케이션 레이어로 전달해주고 ACK 메세지를 보낸다.
그런데 이 rdt2.0 에는 문제점이 있다.
ACK이나 NAK 패킷에 bit error가 발생해도 송신자는 수신자에게 생긴 문제를 알지 못한다.
이렇게 ACK/NAK에 bit error가 발생했을 때 송신자가 할 수 있는 일은 재전송 뿐인데, 만약 실제 값이 ACK이었다면 중복 전송하게 되어 문제가 될 수 있다.
따라서 수신자는 중복전송된 메시지에 대해 핸들링할 수 있어야한다.
rdt2.1: sender, handles garbled ACK/NAKs
- 송신자는 ACK/NAK 패킷에 에러가 발생하면 현재 패킷을 재전송한다.
- 이때 송신자는 각 패킷에 sequence number를 적어둔다.
- 수신자는 수신한 패킷의 sequence number를 보고 중복된 패킷은 버린다.
rdt2.0에서는 송신자의 state는 하나뿐이었는데, rdt2.1에서는 중복패킷을 처리하기 위해 state를 옮겨가며 대기한다.
0번 state(왼쪽)에서는 sequence number 0을 가지는 패킷을 기다리고, 1번 state(오른쪽)에서는 sequence number 1 을 가지는 패킷을 기다린다. 만약 다른 sequence number를 가지는 패킷이 도착하면 해당 패킷은 중복으로 전송된 것이므로 버린다.
- 수신한 패킷에 비트에러가 있다면 NAK 패킷을 보내고 같은 state에서 대기한다.
- 수신한 패킷에 비트에러가 없다면 seqence number를 확인한다.
- 기다리는 sequence number와 다른 sequence number를 가지는 패킷이 도착하면 다시 ACK 메세지를 보내고 같은 state에서 대기한다.
- 기대하는 sequence number를 가진 패킷이 도착하면 ACK 메세지를 보내고 다른 state로 넘어가서 대기한다.
rdt2.2: a NAK-free protocol
rdt2.2는 ACK만을 사용하여 rdt2.1과 같은 기능을 수행하는 프로토콜이다.
수신자는 오류가 발생했을 때 NAK을 보내는 대신 마지막으로 정상적으로 수신한 패킷에 대한 ACK을 보낸다.
예를 들어 0번 패킷을 제대로 수신한 후 1번 패킷에 문제가 생겼다면 rdt2.1에서는 1번에 대한 NAK 패킷을 보내지만, rdt2.2에서는 0번 패킷에 대한 ACK 패킷을 보낸다.
송신자는 ACK 메세지를 받으면 sequence number를 보고 중복된 ACK 인지를 체크한다.
중복된 ACK 패킷이라면 그건 NAK 패킷과 같은 의미를 지닌다. 👉현재 패킷을 다시 전송한다.
rdt3.0: channels with errors and loss
위의 상황에서는 underlying channel이 bit error만을 일으킬 수 있다고 가정했다.
이제는 underlying channel에서 패킷을 잃어버릴 수도 있다고 가정한다. (data, ACK 패킷 모두에 대해 lose가 발생할 수 있음)
패킷이 lose된 경우 수신자는 아무것도 받지 못했기 때문에 할 수 있는 것이 없다. 따라서 이를 해결해주지 않으면 송신자도 ACK 메세지를 기다리고 수신자도 데이터를 기다리며 아무도 진행하지 못하는 상황이 생길 수 있다.
이를 해결하기 위해 송신자는 일정 시간만큼만 ACK메세지를 기다리고, 해당 시간이 지날때까지도 ACK 메세지를 받지 못하면 그냥 다시 전송하도록 한다.
하지만 packet 이 loss된게 아니라 패킷은 정상적으로 보내졌지만 delay가 발생하여 일정 시간 안에 ACK메세지가 오지 않은 것일 수도 있다. 이 경우 timeout이 지난 후 재전송된 패킷은 중복 전송된 것이다. 하지만 이는 rdt2.1에서 처리한 것과 같이 sequence number를 통해 대처될 수 있으므로 상관없다.
rdt3.0 sender 측의 FSM은 rdt2.2와 같이 4개의 state로 구성된다.
- 초기에는 그림의 왼쪽 위 state에서 패킷을 보내라는 호출이 오기를 기다린다.
- 이 상태에서 rdt_send가 호출되면 sequence number를 0으로 하여 패킷을 만들어 보내고, 타이머를 시작한다.
- 오른쪽 state로 넘어가 방금 보낸 0번 패킷에 대한 ACK 메세지가 오기를 기다린다.
- 여기서 패킷을 받았는데 패킷에 bit error가 있거나 1번 패킷에 대한 ACK(중복 ACK) 이라면 아무것도 하지 않는다. (여기서 바로 재전송을 해도 되지만 위의 FSM에서는 그냥 가만히 있다가 timeout에 의해 처리되기를 기다리는 것이다.)
- 타이머가 timeout되면 패킷을 재전송하고 타이머를 재시작한 후, 같은 state에서 대기한다.
- 도착한 패킷이 0번 패킷에 대한 ACK이고 bit error도 없다면 타이머를 멈추고 1번 패킷을 보내기 위한 state(오른쪽 아래 state)로 넘어간다.
- 1번 패킷에 대한 state들 (아래쪽 state들)은 위와 동일하게 동작한다.
- 데이터 전송 (rdt_send)에 대한 호출을 기다리고 있는 state (Wait for call * from above)에 있을 때, rdt_rcv를 통해 ACK 메세지가 도착하면 이는 무시한다. 👉이런 상황이 발생하는 경우는 너무 이르게 timeout이 되어 패킷이 재전송된 후, 정상적인 ACK이 도착하여 다음 state로 넘어간 상황에서 재전송된 패킷에 대한 ACK이 도착하는 상황이다.
Performance of rdt3.0
rdt3.0은 올바르게 동작하지만, 성능 상으로 문제가 있다.
예를 들어 propagation delay가 15ms일 때, 1Gbps 링크에 8000bit 패킷이 전송되는 상황을 생각해보면 transmission delay는 L/R = 8000 bits / 10^9 bits/sec 으로 8microsecs이 나온다. 이는 15ms인 propagation delay와 비교해서 매우 작은 값이다.
rdt3.0은 stop-and-wait 방식으로 동작한다. 즉 송신자는 한번 보낸 후 수신자로부터 ACK을 받을 때까지 기다린다.
따라서 sender의 utilization을 계산해보면 다음과 같다.
transmission delay가 L/R =0.008 ms, RTT = 2 * propagation delay = 30 ms 이다.
transmission delay동안만 sender가 사용되므로 사용된 시간 / 전체 시간을 계산하면 0.008 / 30.008 = 0.00027이 나온다.
이는 네트워크 프로토콜이 physical resource 의 사용을 제한하는 것이다.
Pipelined protocols
pipelined protocol을 통해 위의 성능 문제를 개선하 ㄹ수 있다.
- Pipelining : 송신자가 아직 ack되지 않은 다수의 패킷을 허용하는 것이다. 즉 한번 보낸 패킷에 대한 ack이 올때까지 놀면서 기다리지 않고 계속해서 패킷을 보낸다.
- Pipelining protocol : go-Back-N, selective repeat
위의 그림에서는 sender가 최대 3개의 패킷을 기다리지 않고 보낼 수 있는 경우이다.
Pipelined protocol에서 sender는 N개까지의 ack되지 않은 패킷을 파이프라인에 보유할 수 있다.
Go-Back-N 프로토콜 : 수신자가 오직 cumulative ack만을 전송한다. 즉 연속되지 않고 중간을 건너뛰어 들어온 패킷에 대해서는 ack 메세지를 보내지 않는다. 또한 송신자는 가장 오래된 unacked packet에 대해 타이머를 유지하며, 타이머가 timeout되면 모든 unacked 패킷을 재전송한다.
Selective Repeat (SR) 프로토콜 : 수신자는 각 패킷에 대한 개별 ack을 전송한다. 그리고 송신자는 개별 unacked 패킷에 대해 타이머를 유지하며, 타이머가 timeout되면 해당 패킷을 재전송한다.
Go-Back-N
1. sender
N개의 연속된 unack'ed 패킷이 허용된다.
위 그림과 같이 크기가 N짜리의 윈도우가 있다고 생각하면 윈도우 범위 안에 들어오는 패킷들만 고려하면 된다.
윈도우 왼쪽의 초록색 칸들은 모두 ack된 패킷들이다. 윈도우 안에 있는 노란색과 파란색 칸은 사용될 수 있는 칸들이고 노란색 개수만큼의 패킷은 보내졌지만 아직 ack되지 않았고 파란색 개수만큼의 패킷이 더 보내질 수 있다.
노란색 패킷에 대한 ACK이 도착해 초록색으로 변하면 연속적으로 ACK된 패킷들은 모두 윈도우 밖으로 빠질 수 있으므로 윈도우가 오른쪽으로 이동할 수 있다. 그러면 사용가능한 파란색 칸이 늘어날 수 있다.
또한 아직 ACK되지 않은 보내진 패킷 중 가장 오래된 패킷에 대해 타이머를 유지하며 타이머가 timeout되면 그것보다 높은 seq #을 가지는 모든 패킷을 재전송한다.
Selective Repeat
수신자가 올바르게 수신된 패킷들을 개별적으로 수신한다. (순서대로 들어오지 않더라도 수신자가 해당 패킷을 버리지 않고 버퍼링해둠)
그리고 아직 ACK이 오지 않은 모든 패킷에 대해 타이머를 유지하며 개별 패킷을 재전송한다. (모든 패킷을 재전송하지 않음)
👉송신자 측의 프로토콜
- 데이터 송신 호출이 들어오면, 만약 윈도우에 아직 사용가능한 seq#이 있는 경우 전송함. (없다면 전송하지 못함)
- n번째 패킷에 대한 타이머가 timeout되면 해당 n번째 패킷만 재전송하고 타이머를 재시작함.
- n번째 패킷에 대한 ACK이 왔을 때, n이 윈도우 범위 내에 있다면 해당 패킷을 수신했다고 체크해둔다. 그리고 만약 n이 가장 작은 unACKed 패킷이라면 윈도우를 다음 unACKed seq#까지 이동시킨다.
👉수신자 측의 프로토콜
- 패킷이 들어오면 ACK을 보내고, out-of-order 패킷이 들어오면 버퍼링해둔다.
- in-order 패킷이 들어오면 아직 수신하지 않은 패킷이 있는 곳까지 모든 버퍼링된 패킷도 같이 올려준다.
SR - 딜레마
위의 상황은 sequence #의 범위가 0~3이고 window 사이즈가 3인 상황이다.
하지만 위처럼 sequence #의 범위에 비해 window 사이즈가 너무 크게 잡히는 경우 문제가 발생할 수 있다.
(b)번의 경우에는 마지막에 보낸 0번패킷을 sender와 receiver가 동일한 패킷을 바라보고있지만, (a)번의 경우에는 sender는 첫번째 0번 패킷을 다시 보내지만 receiver는 다음 0번째 패킷을 수신한 것으로 인식한다.
'컴퓨터 네트워크' 카테고리의 다른 글
02. 컴퓨터 네트워크 - Application Layer (0) | 2022.08.18 |
---|---|
01. 컴퓨터 네트워크 - Introduction (0) | 2022.08.15 |