rcv : receiver
app : application
3.1 트랜스포트 계층 서비스와 원리
- 트랜스포트 계층 프로토콜은 서로 다른 호스트들 상에서 동작하는 응용 프로세스들 사이에 논리적 통신(logical communication)을 제공한다.
-송신 측(send side)에서는 응용 계층으로부터 온 메세지를 세그먼트(segment)로 쪼갠(break) 다음, 헤더를 추가하여 네트워크 계층으로 보낸다.
-수신 측(rcv side)에서는 네트워크 계층으로부터 온 세그먼트(segment)를 재조립(reassemble)한 뒤 헤더를 제거하여 응용 계층으로 보낸다.
-인터넷에서 app은 TCP와 UDP, 두 가지 프로토콜을 사용할 수 있다.
3.1.1 트랜스포트 계층과 네트워크 계충 사이의 관계
-트랜스포트 계층 프로토콜이 서로 다른 호스트들 상에서 동작하고 있는 프로세스들 사이의 논리적 통신을 제공하는 반면, 네트워크 계층 프로토콜은 호스트들 사이의 논리적 통신을 제공한다.
-비유를 하자면, 멀리 떨어진 두 집에 아이들이 반대편 집의 아이들과 편지를 주고 받을 때를 가정하자. 각각의 집에서는 편지를 모아서 우체통에 넣는 일을 하는 아이가 한 명씩 있다. 아이들을 편지를 그 일을 맡은 아이에게 주고, 편지를 모은 아이는 그 편지를 우체통에 넣어 보내고, 우체국에서 오는 반대편 집에서 보낸 편지를 가져와 아이들에게 나누어주는 일을 한다.
집을 호스트, 아이들을 프로세스라고 하고 편지를 메세지라고 한다면, 우편 당번은 트랜스포트 계층이고, 우체국은 네트워크 계층이라고 할 수 있다.
3.1.2 인터넷에서의 트랜스포트 계층
-트랜스포트 계층은 비신뢰적(unliable)이고, 비연결형(unorder) 서비스를 제공하는 UDP와 신뢰적(liable)이고, 연결형(inorder)서비스를 제공하는 TCP를 제공한다.
-네트워크 계층 프로토콜은 IP(internet protocol)인데, IP는 호스트들간에 논리적 통신을 제공하는 최선형(Best-effort) 전달 서비스이다. IP는 세그먼트를 전달하기 위해 최선의 노력을 하지만 어떠한 보장(데이터의 무결성이나 세그먼트의 순서 보장)도 하지 않는다.
-TCP와 UDP의 가장 기본적인 기능은 IP전달 서비스를 두 프로세스들 간의 전달 서비스로 확장하는 것이다. 이 것을 다중화(Multiplexing)와 역다중화(demultiplexing)라고 한다.
-UDP는 헤더에 오류 검출을 포함함으로써 무결성 검사를 제공한다.
-TCP는 무결성 검사 뿐만이 아니라 흐름제어(flow control)와 혼잡제어(congestion control), 순서번호/확인응답/타이머 등을 사용함으로써 데이터의 신뢰적인 전송을 제공한다.
-TCP 혼잡 제어(congestion control)은 app에 제공되는 서비스이다. 각각의 TCP연결이 링크의 대역폭을 공평하게 공유하도록 한다. 이것은 과도한 양의 트래픽으로 링크가 폭주하는 것을 방지한다.
3.2 다중화와 역다중화
-여러 app 프로세스로부터 데이터를 받아 세그먼트를 생성하고 헤더를 추가하여 네트워크 계층에게 넘겨주는 작업을 다중화(Multiplexing)라 하고, 네트워크 계정에서 받은 데이터를 올바른 app 프로세스에게 전달하는 작업을 역다중화(demultiplexing)라 한다.
-TCP와 UDP는 세그먼트 헤더에 소스의 포트번호와 목적지의 포트번호를 포함하여 다중화와 역다중화를 가능하게 한다.
-잘 알려진 포트번호(well-known port number) : 0~1023까지의 포트번호. HTTP나 FTP등에 미리 예약되어 있다.
-세그먼트에 포트번호가 두개 필요한 이유 : 만약 목적지에서 같은 포트번호를 가진 프로세스가 두개 이상 동작하고 있다면, 목적지의 트랜스포트 계층 프로토콜은 어느 프로세스에 세그먼트를 줘야 할지 모르게 된다. 따라서 세그먼트에 출발지의 세그먼트를 보낸 프로세스의 포트번호까지 포함함으로써, 해당 세그먼트가 어느 프로세스에 가야 하는지 알게 된다.
-두 개의 클라이언트가 같은 소스 포트번호를 설정하고 서버에 세그먼트를 보내면, 세그먼트의 헤더에 있는 두 포트넘버가 동일하기 때문에 생길수도 있지만, IP 데이터그램(네트워크 계층의 데이터 단위)의 헤더에 소스와 목적지의 IP가 포함되어 있기 때문에 결과적으로 혼란이 발생하지 않는다.
3.3 비연결형 트랜스포트 : UDP
-UDP는 트랜스포트 계층 프로토콜이 할 수 있는 최소한의 기능으로 동작한다.
다중화/역다중화 기능과 간단한 오류 검사를 제외하곤 아무것도 하지 않는다.
-UDP는 세그먼트를 송신하기 전에 hand-shake(통신 설정)을 하지 않는다.
그래서 UDP를 비연결형이라고 한다.
*UDP를 쓰는 이유
1.hand-shake, 즉 연결 설정이 없다. 따라서 연결을 시작하기 위한 delay가 없다.
2.연결 상태(connection state)가 없다. 따라서 TCP보다 훨씬 간단하다.
3.패킷 헤더 오버헤드가 적다. TCP는 20바이트의 헤더 오버헤드를 가지지만 UDP는 8바이트의 헤더 오버헤드를 가진다.
4.전송률이 조절되지 않는다. 혼잡 제어 메커니즘이 없기 때문에 링크가 혼잡한 것과 상관없이 보낼 수 있다.
-UDP를 사용할 때, 어플리케이션이 특정한 기능(확인 응답 메커니즘, 재전송 메커니즘)만 갖추고 있다면, 신뢰성을 보장할 수 있다.
3.3.1 UDP 세그먼트 구조
소스 포트 넘버
|
목적지 포트 넘버
|
길이
|
검사합(checksum)
|
응용데이터(메시지)
|
3.3.2 UDP 검사합(checksum)
-검사합은 세그먼트 안에 있는 모든 16비트 워드를 합한 다음, 1의 보수를 수행해서 얻는다.
-수신측에서 검사합이 포함된 모든 워드를 더하고 나면 1로 채워진 합을 얻을 수 있다. 만약 0이 들어 있다면 그 패킷에는 오류가 있음을 알 수 있다. 하지만 UDP는 오류를 발견해도 단지 app에게 경고를 할 뿐이다.
3.4 신뢰성 있는 데이터 전송의 원리
-신뢰적인 데이터 전송 프로토콜에서는 데이터가 변형되거나 손실되지 않는다. 그리고 전송된 순서대로 전달된다.
-rdt_send()는 reliable data protocol의 송신과 관련된 호출이다.
-udt_send()는 unreliable data protocol의 송신과 관련된 호출이다.
-프로토콜이 상위 계층(app계층)에 데이터를 전달하려고 할 때, deliver_data()를 호출한다.
3.4.1 신뢰적인 데이터 전송 프로토콜의 구축
*완전하게 신뢰적인 채널 상에서의 신뢰적인 데이터 전송 : rdt 1.0
-하위의 채녈이 완전히 신뢰적인 가장 간단한 경우.
-FSM : finite-state machine. 변화를 일으키는 이벤트는 평행선 위에, 이벤트가 발생했을 때 취해지는 행동은 평행선 아래에 나타낸다.
-송신 측은 app계층의 호출을 기다리다가 호출되어 데이터를 받( rdt_send(data) )으면, 패킷에 첨부( make_pkt(packet,data) )하고 보낸( udt_send(packet) ) 다.
-수신 측은 network계층의 호출을 기다리다가 호출되어 패킷을 받( rdt_rcv(packet) )으면, 패킷으로부터 데이터를 추출( extract(packet, data) )한 후, 데이터를 app계층으로 전달( deliver_data(data) )한다.
*비트 오류를 가진 채널 상에서의 신뢰적인 데이터 전송 : rdt 2.0
-패킷들이 송신된 순서대로 수신되지만, 패킷에 비트 오류가 생길 수 있다고 가정.
-positive ack(이하 ack)과 negative ack(이하 nak)이 사용된다. ack은 정확히 수신되었다는 것이고, nak은 재전송을 요청하는 것이다.
*ARG(Automatic Repeat reQuest)프로토콜 : 네트워크에서 재전송을 기반으로 하는 신뢰적인 데이터 전송 프로토콜
1.오류 검출 : 검사합(checksum)필드를 사용하여 오류를 검출 할 수 있다.
2.수신자 피드백 : ACK와 NAK을 사용하는 것으로 송신자가 수신자의 상태를 알 수 있어야 한다.
3.재전송 : 송신자가 재전송을 할 수 있어야 한다.
-송신 측은 두가지 상태를 가진다. 상위 계층으로부터의 호출을 기다리는 상태에서, 패킷을 보내고 난 후에는 수신측에서 보내오는 ACK이나 NAK을 기다리는 상태가 된다. 이 상태에서는 상위 계층에서의 호출에 응하지 않는다. 이 상태에서 ACK을 받았을 경우, 상위 계층의 호출을 기다리는 상태로 돌아가고, NAK을 받았을 경우, 해당하는 패킷을 재전송하고 다시 신호를 기다린다. 그래서 rdt 2.0과 같은 프로토콜을 stop-and-wait 프로토콜이라 한다.
-수신 측은 송신측에서 온 패킷에서 오류가 검출되었을 경우, NAK신호를 보내고, 오류가 검출되지 않았으면 상위계층에 데이터를 보낸 후에 ACK신호를 보낸다.
- rdt 2.0에서는 치명적인 결점이 있다. ACK나 NAK 패킷의 변형의 가능성에 대해서는 고려하지 않고 있는 것이다.
*ACK 또는 NAK가 변형되었을 경우 처리 방법
1.ACK 또는 NAK 패킷의 재전송을 요청한다. 하지만 그 재전송마저 변형될 가능성이 있다.
2.패킷에 오류 검출뿐만 아니라 오류로부터의 회복도 할 수 있도록 충분한 검사합(checksum)비트를 추가하는 것이다.
3.왜곡된 ACK 또는 NAK을 받았을 경우 단순히 패킷을 재전송한다. 하지만 수신 측에서 재전송인지 새로운 패킷인지 알 수 없다.
->이 문제를 해결하기 위해 패킷에 순서 번호를 삽입한다.
-rdt 2.1에서는 송신자가 4개의 상태, 수신자가 2개의 상태를 가진다. 이것은 순서번호가 0일 때와 1일때를 구별하기 위해서이다. 순서 번호를 제외한 나머지 이벤트와 동작은 상태가 0일 때와 1일 때가 같다.
-rdt 2.2에서는 NAK 신호 대신에 이전 패킷의 ACK 신호를 보낸다. 즉 송신 측에서 상태가 1인 패킷을 보냈는데 상태가 0인 ACK 신호가 왔다면 재전송을 해야 한다.
*비트 오류를 갖는 손실 채녈 상에서의 신뢰적인 데이터 전송 : rdt 3.0
-실제 네트워크 상에서는 패킷의 손실이 일어난다. ACK 또는 NAK 신호가 왜곡되는 것이 아니라 아예 손실되어 버린다면, 송신측과 수신측은 계속 대기 상태에서 서로의 신호를 기다리고 있을 뿐이다. 이것을 해결하기 위하여 초읽기 타이머(countdown timer)를 사용한다.
-송신자는 패킷이 송신될 때 타이머를 시작하고, 응답이 도착하면 타이머를 멈추고, 타이머가 끝날 때까지 응답이 오지 않으면 재전송을 해야 한다.
-송신 측에서 ACK를 받았을 때, 그 신호가 최근에 전송된 패킷에 대한 응답인지 아니면 그 이전에 전송된 다른 패킷에 대한 응답인지 구분하기 위해서 ACK 패킷에 확인 응답 필드를 추가 시킨다. 그리고 그 필드에 순서 번호를 넣는 것이다.
-패킷의 순서 번호가 0과 1을 왔다갔다 하기 때문에 rdt 3.0을 얼터네이팅 비트(alternating bit)프로토콜 이라고 한다.
3.4.2 파이프라인된 신뢰적인 데이터 전송 프로토콜
-stop-and-wait프로토콜의 경우 실제 네트워크 상에서 그 효율이 엄청나게 낮다. 거리가 먼 두 곳일 경우 보내는 작업을 수행한 다음 그 패킷이 그 먼 거리를 갈 동안 기다리고, 수신측이 처리할 동안 기다리고, ACK/NAK신호가 그 먼 거리를 올 동안 기다려야 한다. 수신측도 마찬가지이다.
-이 문제를 해결하기 위하여 파이프라이닝 방식을 사용한다. 확인 응답을 기다릴 것 없이 다중 패킷을 전송하는 것이다. 물론 이 파이프라이닝 방식을 적용하기 위해서는 순서 번호의 범위가 증가되어야 하고, 송신측과 수신측이 한 패킷 이상을 버퍼링해야 한다.
3.4.3 Go-Back-N(GBN)
-GBN 프로토콜에서는 송신자가 확인 응답을 기다리지 않고 다중 패킷들을 전송할 수 있다. 그러나 응답이 오지 않은 패킷의 최대 혀용수 N보다는 크지 않게 해야 한다.
-가장 오래된 미응답 패킷의 번호를 base라 하고, 아직 사용되지 않은 가장 작은 번호를 nextseqnum이라 하면, 순서번호의 범위는 4개로 나누어 진다. 0에서 base-1까지는 전송된 후 응답이 된 패킷의 번호이고, base에서 nextseqnum-1까지는 전송했지만 아직 응답이 오지 않은 패킷의 번호이다. 그리고 nextseqnum에서 base+N-1까지는 패킷을 보내야 할 때 바로 사용할 수 있는 번호이고 base+N부터는 지금 당장 보낼수는 없는 번호들이다.
-N은 윈도우 크기라고 하고, GBN은 슬라이딩 윈도우 프로토콜이라고 한다.
*GBN에서 송신자는 세가지 타입의 이벤트에 응답해야 한다.
1.상위계층의 호출 시에, 송신자는 윈도우가 가득 찼는지 확인해야 한다. 가득 차 있지 않다면 패킷이 생성되고 송신하면 된다.(그리고 nextseqnum은 한칸 이동하게 된다.) 가득 차 있다면 송신자는 상위 계층으로 데이터를 반환하거나 버퍼링하는등 송신을 지연시킨다.
2.ACK을 수신 했을 경우, 순서 번호 n의 ACK를 수신했을 경우 n까지의 모든 패킷을 올바르게 수신되었다고 생각할 수 있다.(그리고 윈도우와 base는 한칸 이동하게 된다.) 이것은 축적 확인 응답이라 한다.
3.타임 아웃 이벤트 : 타이머가 종료(타임아웃)되면, 송신자는 이전에 전송되었지만 아직 응답되지 않은 모든 패킷들을 다시 송신한다.
-수신자의 동작을 간단하게 하기 위하여 순서가 틀린 패킷들은 전부 버린다. 따라서 따로 버퍼링할 필요가 없다.
3.4.4 선택적 반복 ( Selective Repeat, SR)
-GBN프로토콜에서는 stop-and-wait 프로토콜에서의 채널 이용률 문제를 해결할 수 있다. 하지만 윈도우크기가 크고, 대역폭-지연 결과가 크면 많은 패킷들이 파이프라인에 속하게 되고 불필요한 재전송이 많이 일어날 수 있다.
-SR에서는 수신자에게서 오류가 발생한 패킷들만들 송신자가 재전송하도록 한다.
-수신자는 정확하게 도착한 패킷의 ACK을 반드시 보내야 한다. 만약 그 패킷이 순서에 맞지 않는 것이라 할 지라도. 이전 패킷을 받았다고 응답을 하지 않으면, 송신자는 그 이전 패킷을 계속 보낼수 밖에 없다.