[CS]/[컴퓨터네트워크]

전송계층2 - Reliable한 데이터 전송을 위한 기능들

broship 2021. 3. 1. 16:34

※kocw에서 제공하는 이석복 교수님의 컴퓨터네트워크 수업을 듣고 필기한 내용입니다.

출처를 따로 밝히지 않는 한 전부 해당 수업에서 제공한 자료들이며 제가 작성한 부분에 있어 틀린 부분이 있을 수도 있다는 점 양해바랍니다.

 


Reliable Data Transfer(RDT) 프로토콜


- 기본적으로 tcp는 udp보다 더 많은 것을 제공하는데, 그 중 첫번째는 tcp는 reliable한 데이터를 제공함

- 전송계층 밑에 계층에서 이루어지는 전송은 reliable 하지 않음(Message error, Message loss가 있을 수 있음)

- 전송계층에서 메세지 에러와 유실을 체크해줘야됨

 

그럼 reliable을 보장하는 Reliable Data Transfer(RDT) 프로토콜을 한번 간단한것부터 점진적으로 개발시켜보자

 

 

RDT v1.0: 전송되는 모든 데이터가 에러없고 유실 없음

- sender: 데이터 전송만 하면됨

- receiver: 데이터 받기만 하면됨

 

 

RDT v2.0: 전송되는 데이터가 에러가 생길수 있으나 유실은 없음

- 3가지 기능이 추가되야됨

1. Error detection - add checksum bits 패킷 헤더에 체크섬비트를 추가해서 에러 체크를 해야됨

2. Feedback - 리시버가 에러없는 패킷을 받으면 ACKs(Acknowledgements)를, 에러있는 패킷을 받으면 NAKs(Negative acknowledgements)를 센더에게 전송

3. Retransmission - NAK을 받으면 방금 보낸 패킷 재전송

- 센더 패킷 보냄 -> 리시버 받아서 ack나 nak을 보냄 -> 센더가 nak을 받으면 재전송, ack를 받으면 다음 패킷 전송

 

 

RDT v2.1: 만약 리시버에서 보낸 ACK or NAK가 에러가 생기면?

- 센더가 ack를 받았는지 nak을 받았는지 모르므로 일단 무조건 재전송함

- 그럴경우 리시버가 이게 새로운 패킷인지 아님 센더가 ack를 못받아서 재전송한건지 모름

- 헤더에 Sequence number를 추가(처음 보낸건 0, 그다음은 1, 그다음은 0.... 이렇게 하면 0,1 만 추가해도 됨)

- 리시버는 시퀀스넘버를 확인 후 순서에 맞으면 받고 순서에 맞지 않으면 버림(중복된거 제거 Reveiver discards duplicate packet)

RDT v2.1 예시

sender:

1. seq num added to pkt

2. must check if reveibed ACK/NAK corrupted

3. Retransmit on NAK or corrupted feedback

 

receiver:

1. must check if reveived packet is duplicate

2. send NAK if reveived packet is corrupted, send ACK otherwise

 

 

 

RDT v2.2: NAK을 없애고 ACK만으로 동작하게 함

- 리시버는 무조건 ACK만을 보냄

- 만약 에러난 포켓을 받았을 경우 ACK를 보내되 같은 시퀀스 번호로 보냄

- 센더는 받은 시퀀스 번호로 다음 포켓을 보낼지 아님 재전송할지 결정함

- 즉, 시퀀스번호 만으로 ACK or NAK을 판단

 

 

RDT v3.0: 전송되는 데이터가 에러, 유실 둘다 발생할 수 있음(실제상황)

- 데이터 유실이 발생될 경우, 어느 정도 경과 시간이 지난 후 재전송해야됨

- 이때 Timer가 필요함

- 센더는 "reasonable"한 기간동안 ACK를 기다린 후 재전송 해야됨

- 이때 타이머가 너무 빠를시

장점: 데이터 유실이 발생할 시 빠르게 복구 가능함

단점: 유실이 발생하지 않고 단지 느리게 도착해도 재전송 할수 있음(네트워크 과부화)

- 타이머가 너무 느릴시

장점: 네트워크 과부화를 줄일 수 있음

단점: 데이터 유실 발생 시 복구가 느림

 

그래서 항상 타이머 시간을 어떻게 "reasonable" 하게 잡아야됨

- 지금까지의 RDT로 reliable한 데이터 전송을 보장할 수 있음, 하지만 한번에 하나의 패킷만 전송하고, ACK가 올때까지 아무것도 안하고 있는 등 비효율적인 면이 있음

- 실제로는 한꺼번에 여러개의 패킷을 보내는 구조로 되어있음(파이프라인)

- 파이프라인으로 보내는 방법 2가지:

1. go-Back-N

2. Selective repeat

(이 둘은 실존하는 프로토콜은 아니나, TCP가 이 방법들과 유사하게 사용되고 있음)

 

 

 

GBN (Go-Back-N)


- GBN 방식은 한번에 다수의 패킷을 버퍼에 담아놓고 전송함

- 버퍼의 크기를 window size라고 함, window size 만큼은 피드백을 받지 않고 보내기만함

- GBN 에서 ack는 쌓는형식("ACK11" 은 11번 패킷까지 잘 받았다, 12번 패킷 보내라)

- ACK를 받으면 해당 패킷을 윈도우에서 제거하고 새로운 패킷을 윈도우에 집어 넣음

- 이때 오류나 유실로 패킷 타임아웃이 되면 윈도우의 처음부터 재전송(win size = n일때 오류나 유실로 타임아웃이 되면 n만큼 돌아간다고 해서 go back n)

- ex)

n=4일때 4만큼의 데이터를 한꺼번에 보내고(0,1,2,3), ack0을 받으면 윈도우에서 0을 삭제하고 4를 추가(1,2,3,4) 패킷 1이 타임 아웃되면 다시 1,2,3,4 전송, ack1받으면 윈도우에서 1삭제 5추가(2,3,4,5).....

GBN 동작방식

- 오류,유실 발생시 윈도우 크기만큼 재전송 하는 이유는 receiver가 받은 패킷을 저장할 버퍼를 가지고 있지 않고 자신이 받아야할 시퀀스 넘버만 기다리는 기능만 가지고 있어서 그럼

- 그래서 GBN의 단점은 단 하나의 패킷이 유실되도 윈도우 전체를 재전송 해야한다는것, 실제로는 윈도우 사이즈가 수천개에 다다를텐데 그러면 낭비가 심해짐

 

 

 

Selective repeat


- GBN의 단점을 해결하기 위해 나옴, 리시버가 받은 패킷을 임시 저장할 수 있는 버퍼를 가지고 있음

- 리시버는 순서에 맞게 들어온 패킷이 아니면 일단 버퍼에 저장

selective repeat 동작방식

- 버퍼에 계속 담아두다가 센더가 재전송한걸 받으면 버퍼안에있는 모든 패킷을 어플리케이션에 올리고 ACK 보냄

 

 

- 여기서 문제가 될수 있는 점은 시퀀스 넘버가 패킷 갯수만큼 커질 수 있다는점(전송할 실제 데이터가 아닌 헤더에 들어가는 내용은 최대한 최소화해야됨)

해결방법:

- 최소한의 시퀀스넘버를 잡고, 그걸 반복해서 사용한다(0,1,2,3,01,2,3,....)

- 시퀀스 넘버를 너무 작게 잡으면, 패킷은 잘갔는데 ACK가 유실될 경우 센더가 재전송했는데 리시버가 그걸 재전송된게 아니라 다음 패킷인줄 알게됨

- 적당한건 win size X 2정도, 그쯤 어딘가

 

 

여전히 해결해야 할 문제:

- 윈도우 안에 있는 각각의 패킷마다 타이머가 있다는 것

- 실제로 전송할땐 프로세스도 수십개에 각 윈도우 사이즈가 수천개씩 될텐데, 전부 타이머가 있으면 CPU가 버티지 못함

 

TCP는 이 문제를 해결하고자 윈도우 안에 대표 타이머 하나만 두고, 리시버도 대표 ACK 하나만을 보냄