[컴퓨터 네트워크] 3. Transport Layer(2)

김민석·2021년 4월 14일
1

컴퓨터 네트워크

목록 보기
10/12

3.1 principles of reliable data transfer

어떻게 data를 reliable 하게 보내는가

  • 어플리케이션 레이어 입장에서는 보내면 reliable이 보장 된다고 생각한다.
    -> 트랜스포트 레이어에서 이 부분을 구현해 줘야함. (아래 레이어들(링크 레이어)은 unreliable한 상황)
    -> 그림의 네가지 함수들을 통해 reliablility 보장(rdt_send(), udt_send(), rdt_rcv(), deliver_data())
  • Unreliable channel의 특징이 reliable data trnasfer protocol(rdt)의 복잡성을 결정한다.
    -> 많이 unreliable 하다면 복잡해지겠고, 어느정도 커버 해준다면 덜 복잡해 지고.

동작하는 함수들


-> 샌더와 리시버가 동작하는 방법을 fsm형태로 설계(fsm : 시스템 동작 설명하는 방법)

rdt 1.0: reliable transfer over a reliable channel

  • reliable한 채널 위에 만든 경우(아래 래이어가 reliable한 경우)
  • underlying channel이 완벽하게 reliable한 경우
    -> bit error가 없다.
    -> 패킷의 loss가 없다.
    -> 할게 딱히 없다.

rdt 1.0: FSM specification

  • sender : 어플리케이션 레이어가 데이터를 보내주면 패킷을 만들고(데이터에 헤더를 붙임) 패킷을 아래 레이어로 전송한다.
  • receiver : 아래 레이어로부터 패킷을 받으면 패킷에서 헤더 떼서 데이터 추출하고 데이터 전달

rdt 2.0: channel with bit errors

  • 비트 에러가 발생하는 경우
    -> 아래 채널이 패킷의 비트를 바꾼 경우
    -> checksum을 통해 bit error를 detect한다.(오류있다는 사실만 알지 어디서 틀린지는 모름)
  • 에러를 복구하는 방법
    -> 에러가 있는 패킷을 버리고 송신자에게 알려서 재전송 받아야 한다.
    -> 이것을 위해 feedback을 해 줘야 한다.(control message를 receiver가 sender로 보내줌)
    -> acknowledgements(ACKs) : sender가 receiver쪽으로 패킷을 보내면 receiver가 잘 받았다는 내용이 답긴 작은 패킷을 sender쪽으로 보냄.
    -> negative acknowledgements(NAKs) : 패킷이 왔는데 checksum을 보니 에러가 있어서 에러가 있다는 내용을 sender쪽으로 보냄.
    -> sender 입장에서 NAK이 오면 에러가 있다는 의미이므로 재전송하고 ACK이 오면 잘 받았다는 의미이므로 그냥 넘어감.

rdt 2.0: FSM specification

  • sender
    ->데이터를 받으면 패킷을 만들고 보내준 후 ACK이나 NAK을 기다리는 상태로 변경(receiver의 응답 대기)
    -> receiver로부터 패킷을 받고 만약 받은 패킷이 NAK이면 재전송
    -> 패킷 받고 만약 ACK이라면 아무런 action 취하지 않고 상태만 변경
  • receiver
    -> 패킷을 받고 받은 패킷이 corrupt라면(checksum을 확인해서 에러 있는 경우) NAK을 보냄
    -> 받은 패킷이 notcorrupt라면 데이터를 추출하여 전송해 주고(어플리케이션 레이어로), sender에게 ACK을 보냄

문제점

  • ACK이나 NAK이 제대로 올 것이란 보장이 없다(얘네마저 비트에러가 있을 수 있음).
    -> ack이던 nak이던 다시 전송하면됨
    -> 근데 리시버에서 이미 왔던건지, 새건지 모름
    -> 그저 다시 전송하면 duplicate 가능성 있음
  • duplicate 해결 방법
    -> sender는 ACK,NAK에서 corrupt가 일어면 패킷을 재전송 한다.
    -> sender는 각각의 패킷에 sequence number를 붙임
    -> duplicate인지 아닌지 알 수 있음
    -> receiver는 받은 패킷이 왔던것이면 버리고 새것이면 처리해줌

예를들어 sender가 receier에 패킷을 보내서 receiver가 ACK을 보내줬는데 sender에서 못받았다고 하자.
-> 그냥 다시 패킷을 재전송하면 receiver 입장에서 새 패킷인지 왔던 패킷인지 모른다.
-> 그래서 sender가 숫자를 붙여서 0번 패킷을 보낸다.
-> receiver가 받아서 ACK을 보내줬는데 만약 sender가 못받으면
-> sender는 다시 0번 패킷을 보낸다.
-> receiver 입장에서 0번은 왔던거니까 그냥 버리고 ACK만 보내준다.

rdt 2.1: handles garbled ACK/NAKs

  • 왜곡된 ACK/NAK 처리하기 -> 위에서 발생한 문제점 해결을 위해 sequence number를 이용
    -> sequence number를 나타내기 위해 1비트만 사용한다(0,1만 구별 가능)
    -> 이것을 통해 ACK/NAK 손실을 해결한다.

rdt 2.1: FSM specification

  • sender

    -> 첫 상태 : 데이터 받으면 헤더에 0 붙여서 패킷 만들고 보내고 상태 변경
    -> 뭔가 받았고, corrupt이거나 NAK이면 재전송하고 상태 유지(상태 : ACK이나 NAK 0를 기다림) / 뭔가 받았고, notcorrupt이고, ACK이면 상태 변경
    -> 데이터 받으면 헤더에 1 붙여서 패킷 만들고 보내고 상태 변경
    -> 위 내용 반복

  • receiver

    -> 0번 기다리는 상태 : 뭔가 받았는데 문제없고(notcorrupt), 0번이면 데이터 손질해서 애플리케이션 레이어로 보내주고, ACK 만들어서 샌더로 보내주고 상태 변경
    -> 문제있으면 NAK 만들어서 보냄 / 문제 없는데 1번이면 ACK은 만들어서 보내줌
    -> 둘 다 애플리케이션쪽으로 보내는거 없음, 상태도 변경 아님.(문제가 있거나 이미 받은 패킷이니까)
    -> 1번 기다리는 상태 : 위 내용 반복

논의점

  • sender
    -> 패킷에 sequence number를 붙인다.
    -> 0,1 만 써도 충분하다. -> stop and wait을 하기 때문
    -> 받은 ACK/NAK 이 corrupte인지 확인 해야 한다.
    -> ACK이 와야 다음 패킷을 보낸다.
    -> 상태가 두배 많다(전에 온 넘버 기억, 어떤 넘버가 올지 대기)
  • sender
    -> 받은 패킷이 중복된것인지 확인해야한다.

rdt 2.2: a NAK-free protocol

  • 일반적으로 NAK을 안쓰고 ACK만 쓰는 경우가 많음 -> NAK을 안쓰도록 한거
  • 기능은 2.1과 같지만 NAK을 사용하지 않는다.
  • NAK 대신에 ACK 활용 : receiver는 제대로 받은 마지막 패킷에 대한 ACK을 보내준다.
    -> 이것을 위해 ACK에 sequence number 넣어서 보내줌
  • sender에서 받은 중복된 ACK이 NAK의 기능을 한다.
    -> 중복된 ACK 받으면 현재 패킷 재전송함

rdt 2.2: FSM specification

-> 2.1에서 바뀐 부분만 표현함

  • sender
    -> ACK 0를 기다리는 상태에서 corrupt이거나 받은 ACK이 1번이면 재전송 하고 상태 유지
    -> corrupt아니고 0번 ACK이면 다음 상태로 변경
  • receiver
    -> 1번 패킷을 받으면
    -> 상태 변경하면서(1->0을 기다리는 상태) sndpkt(ACK1을 가진 패킷) 만들고 상태 변경
    -> 0 기다리는 상태에서 오류가 있거나 받은 패킷이(샌더로부터) 1번이면 sndpkt를 보내고 상태 유지
    -> sndpkt에는 ACK1이 저장되어 있으니까 샌더 입장에서 재전송 해 줘야 하는거

rdt 3.0: channels with errors and loss

  • 2번대는 비트에러에 관한 내용
  • 3.0 : 패킷로스도 발생할 수 있는 경우(라우터에서 오버플로우가 발생해서(들어오는게 나가는거보다 빨라서) 버퍼가 꽉차서 drop되는 경우)
    -> 샌더는 보냈는데 리시버가 못받은 경우
    -> checksum, seq num, ACK, 재전송은 도움이 될 순 있지만 충분하지 않다.
  • 접근
    -> receiver는 아무것도 안받았으니까(패킷이 안온거니까) 동작 안함.
    -> sender는 패킷을 보낸 후 ACK이 올때까지 적절한 시간동안 기다린다.
    -> 이 시간동안 ACK이 안오면 재전송한다.
    -> 어떤 이유로 손실이 아니라 느리게 간 것이라면 그냥 재전송 했을 경우 duplication이 발생한다.(seq num으로 방지할 수 있음)
    -> 타이머를 구현해야 한다.

rdt 3.0: sender FSM specification

-> 초기상태 : 패킷 만들고 전송 한 후 타이머 시작해서 다음 상태로 넘어감
-> 오긴 왔는데 시퀀스 넘버가 다르거나 문제가 있으면 타이머는 그냥 흘러가도록 놔두고 상태 유지
-> 타임아웃이 걸리면 재전송하고 타이머 다시 시작 하고 상태 유지
-> ACK이 제대로 오면 타이머 스탑하고 다음 상태로 넘어감

동작과정

  • (d) 이미지
    -> 타이머를 너무 짧게 하면 제대로 보내지긴 하는데 불필요한 재전송이 많아진다
    -> performance 측면에서 안좋다.
    -> 반면 너무 길게 하면 loss 발생 했을때 복구까지 너무 오래 걸림
    -> 적당한 타이머를 구현하는게 중요

performance of rdt 3.0

  • rdt 3.0은 동작은 잘하지만 성능이 안좋다(stop and wait 때문)

(예시)

  • 전송속도 1 Gbps / 전파속도 15ms / 8000bit의 패킷 보냄 가정
  • sender와 receiver 사이가 회선으로 연결되있다고 가정(중간에 라우터 없이)
    -> 전송시간 : 패킷 내보내는데 걸리는 시간 : 8 microsec
    -> 전파시간 : 한 패킷이 끝까지 가는데 걸리는 시간 : 15ms
    -> 보내는데 총 시간 = 전송시간 + 전파시간 = 15.008ms
    -> ACK은 비트수가 작기 때문에 전송시간 매우 작다고 판단해서 무시하고 전파시간만 고려
    -> 따라서 패킷이 가는데 걸리는 시간 + ACK이 오는데 걸리는 시간 = 15.008 + 15 = 30.008ms
    -> 8000비트 보내고 ACK 받는데 30.008ms 걸리는거
    -> 효율성이 매우 떨어진다. (효율성이 1이 제일 좋음)
    -> 즉 하나 보내고 하나 돌려 받는 동안 기다리는 시간이 매우 아깝다

stop-and-wait operation

  • 하나 보내고 하나 받고 하는 방식
  • 전체 시간(RTT + L/R)에 비해 파일 전송에 걸리는 시간 L/R이 너무 짧다.

Pipelined protocols

  • 파이프라인 프로토콜(<-> stop and wait)
    -> 한꺼번에 여러개의 패킷을 보내서 여러개의 ACK을 받자.
    -> 보내지는 여러 패킷들을 구별하기 위해 sequence 넘버가 늘어나야 한다.
    -> 버퍼링이 필요하다.
    -> go-Back-N, selective repeat 이 많이 사용된다.


정해진 개수의 여러개의 패킷을 보내고, ACK이 오는대로(하나씩 올 때 마다) 다음 패킷을 보낸다.
-> 효율성 정해진 개수배 만큼 늘어난다.
-> performance 측면에서 좋아진다.
-> 단점 : 프로토콜이 복잡해진다.

Pipelined protocols: overview

  • Go-Back-N
    -> 파이프 라인에 N개까지 ACK을 받지 않은 패킷을 보낼 수 있음.
    -> Cumulative ack 사용(리시버는 중간에 비는 번호 없이 다 받았을 때만 ack을 보낼 수 있음. 순서대로 받다가 하나라도 안오면 그 이후로는 패킷 오더라도 ack 안보냄).
    -> 타이머 하나 사용(ack 못받은 패킷중 가장 오래된 패킷이 가지고 있음. Expire(time out) 되면 모든 패킷 재전송)
    -> 같이 보내진 패킷들을 한번에 관리해서 하나라도 안오면 ack 안보내니까 샌더에서 타임아웃 돼서 안온 패킷부터 재전송 하게 된다.
  • selective repeat
    -> 안보내진 패킷만 재전송하자.
    -> Individual ack 사용(따로 관리해서 받은 패킷만 ack 보내고 못받은 패킷은 ack 안보내줘서 못받은 패킷만 재전송 할 수 있게).
    -> 각각의 패킷에 대한 타이머 사용.(ACK이 오면 타이머 끄고 expire 되면 그 패킷만 재전송 하면 됨)
    -> 타임아웃 된 패킷에 대해서만(ack 못받은 패킷) 재전송

Go-Back-N

Sender

  • k-bit를 써서 패킷들을 seq num을 통해 구별한다.
  • 필요한 parameter : send_base, window size, nextseqnum

    -> window size : n개까지 한번에 보낼수 있다라는 파라메터
    -> send_base : 전송할 수 있는 윈도우의 가장 앞의 패킷
    -> nextseqnum : 다음으로 보내질 패킷의 시퀀스 넘버
    -> 그림에서 앞에 노란색은 보냈지만 송신자로부터 아직 ack안온 것들
    -> 뒤에 파란색은 데이터가 없어서 보낼 수 있지만 아직 안보낸거.
    -> 맨 앞 초록색은 보내고 ack 받은거.
    -> 슬라이딩 윈도우 사용(사이즈는 유지하고 한칸씩 옆으로 이동)
  • ACK(n) : n번까지 ACK을 다 받았다는 의미 -> cumulative ACK
    -> ack이 날아가서 못받더라도 패킷만 잘 전달 됐으면 그 다음 ack이 오면서 앞에꺼 까지 acknowledge 해 줄 수 있다. 이런식으로 누적ack 사용
    -> 예를들어 패킷 1,2,3,4 를 보내고 다 잘 전달 됐는데 2,3번 ACK이 날라간 경우 ACK(4)를 통해 앞에것들이 잘 왔다는 것을 알 수 있다.
    -> duplicate ack을 받을 수 있음
  • oldes in-flight packet 에 대한 타이머
    -> in-flight = outstanding = set but not acked
    -> 아직 ack 못받은 애중 시퀀스 넘버가 가장 앞에 있는거
    -> 얘에 대해서 타이머를 가지고 있다 = 타이머를 하나만 가지고 있다.
  • timeout(n) : n이라는 시퀀스 넘버에서 타임아웃이 걸렸으면 n부터 전부 다시 보냄

GBN: sender extended FSM

  • 하나의 스테이트
    -> 이벤트에 따른 반응만 있다.
  • 애플리케이션에서 데이터를 보내줬을 때
    -> 만약 nextseqnum이 base + N 보다 작으면(윈도우 안에 존재하는 경우) 패킷에 헤더 붙이고 네트워크 레이어로 보낸다.
    -> 이 과정을 진행 한 후 만약 base == nextseqnum 이면(in-flight packet이면) 타이머 시작
    -> nextseqnum++
    -> 만약 윈도우 안에 있는 애들이 다 보내진 경우라면 refuse(버퍼링)
  • timeout 일 때
    -> 타이머를 다시 시작하고 베이스 부터 nextseqnum-1 까지 데이터를 다시 전부 재전송한다.
  • 데이터를 받고 notcorrupt 일 때
    -> 베이스에 ack 넘버 + 1을 해준다.
    -> 예를 들어 현재 베이스가 5인데 ACK(6)이 오면 베이스를 7로 해준다.
    -> 만약 베이스가 nextseqnum이면 타이머 스탑, 아니면 타이머 0부터 재시작
  • ack을 받았는데 corrupt일 때
    -> 아무 동작 안함

GBN: sender extended FSM

  • 타임아웃이 걸리면 어차피 sender가 다 보내주기 때문에 기억할 필요가 없다
    -> 단순함
  • Ack-only : 어떤 데이터가 오면 항상 ACK을 보내주는데 cumulative ack이기 때문에 in order(중간에 빵구 없이 순서대로 온것)중 시퀀스 넘버가 가장 큰거 보내준다.
    -> 예를들어서 3번 빵구면 expectedseqnum인 A2만 ack으로 보냄. 4번이 와도 2번 보냄. 그리고 2번 이후에 오는 패킷들은 걍 다 버림(discard)
    -> 샌더 입장에서 똑같은 번호를 가진 ack을 중복하여 받을 수 있다.
    -> expectedseqnum만 기억하면 된다.
  • out-of-order packet
    -> 빵구 이후에 오는 패킷들(순서에 안맞게 온 애들 예를들어 123와야 하는데 132오는 패킷도 포함)은 버리고 버퍼링하는것도 없음.
    -> ack을 보내주긴 함.

  • 초기 상태 : expectseqnum=1로 해 주고 그 번호로 ACK 만든다.
    -> 올것들이 제대로 온 상황 : 처리 잘 해주고 보내주고 expectseqnum++
    -> default(에러가 있다거나 패킷이 깨졌거나 원하는 번호가 아니거나 등) : 이전에 만들었던 패킷 보내줌
    -> 예를들어 현재 ACK(3)까지 만들어진 상황에 5번 패킷이 오면 ACK(3)을 보내줌. 만약 패킷이 깨져서 와도 ACK(3) 보내줌.

동작 과정

출처 및 참고
Computer Networking A Top-Down Approach 7-th Edition / Kurose, Ross / Pearson
서강대학교 기초컴퓨터네트워크 강의자료

profile
김민석의 학습 정리 블로그

0개의 댓글