오래 못 할 짓 하지 않기

[ 네트워크 ] 11. Transport layer : UDP(2) 본문

3학년 2학기/네트워크 (Network)

[ 네트워크 ] 11. Transport layer : UDP(2)

쫑알bot 2024. 10. 7. 13:03
728x90

Checksum

📌 목적

 Segment 전송 도중에 데이터에 에러가 났는지 감지하기 

 

 

보낼 땐 5 , 6 의 값이 들어가서 sum이 11 이었다.

      > Sum에 11을 담아서 보냄

 

받았을 땐 4 , 6 값이 있었는데 

      > 받은 Sum 11이랑 계산해본 10이랑 비교

      > 값이 다르다 = 전송 도중에 에러가 발생했다.

 

 

Sender)

- Segment에 Sum ➡️ 1의 보수로 변환 ➡️ Checksum 담아서 보내기

 

 

Receiver)

- 받은 Segment에 있는 Checksum이랑 

  계산한 Checksum 비교하기

 

 

예제)

 

문제 없는 경우

 

 

이러면 문제가 없는데

문제를 만들어보자

 

뒤에 두 자리가 10 에서 01로 바뀌고 , 01이 10으로 바뀌었다고 해보자

 

데이터는 바뀌었지만 Sum이나 Checksum은 바뀌지 않았다.

 

이 예시처럼 서로 같은 영역에 같은 형식으로 바뀌었을 때는 (교체 느낌)
데이터는 바뀌었지만 checksum으로 감지가 되지 않을 수도 있다

 

 

 

* checksum이 UDP에서만 쓰이는 건 아니다. 

 


Principles of reliable data transfer

 

Reliable data transfer 상황에서는

Data가 항상 올바르게 전송되기 때문에 크게 고려할 게 없다.

 

왼쪽이 우리가 구상하는 reliable 전송이고

오른쪽이 실제로 작동하는 reliable 전송이다.

 

unreliable한 channel을 통해서 주고받지만

channel 앞뒤로 reliable 한지 확인하는 단계가 있다.

 

해당 단계에서는 Data Loss, Corrupt, Reorder data 에 관한 작업을 거친다.

 

 


Sender와 Receiver 측의 Reliable Data Transfer (rdt) 프로토콜을 점진적으로 만든다고 해보자.

Sender가 Receiver에게 데이터를 보내는 상황이라고 생각하자.

 

돌아가는 방식은 아래와 같다.

= 위에 일이 일어나면, 아래 일을 실행한다.

 

[ 전제 조건 ]

Sender는 Receiver가 100% 정확히 받았다는 사실을 확인해야

다음 패킷을 보낸다.

 

> 만약에 error가 나면 어떻게 함?

다시 보내달라고 말하든지, Sender가 눈치껏 다시 보내줘야한다.

 

 

 

 

여러 버전이 있어도 기본적인 작동 방식은 다음과 같다. 

 

 

 

흐름은 다음과 같다.

 

1. Sender Application 계층 에서 rdt_send() 명령어 실행

2. Transfer 계층에서 프로토콜을 이용하여 udt_send()로 패킷 전송

3. rdt_rcv() 를 통해 Receiver의 Transfer 계층에서 패킷을 받음

4. deliver_data() 를 이용해 Receiver Application 계층으로 보냄

 

 


rdt 1.0

 

완벽하게 안정적인 통신이다.

- Bit error 없음

- Packet loss 없음

 


rdt 2.0

: bit error가 발생할 수 있는 Channel을 사용한다.

따라서 error가 발생했을 때 커버하는 부분을 추가해야 한다.

 

사람끼리 대화 중에 소통이 잘 안 되면 어떻게 하나?

➡️ 다시 말해달라

 

패킷도 똑같다. Error가 발생했을 때

- 다시 요청해서 받든지

- Sender에서 알아차리고 다시 보내주기

 

여기에서 서로 제대로 받았는지 확인하는 과정에서 쓰이는 게 

ACKs ( acknowledgements ) 이다.

➡️ Receiver가 Sender에게 패킷을 잘 받았고, 문제가 없다고 전달하는 것

 

반대로 Sender에게 해당 패킷이 문제가 있다고 알려주는 것이

NAKs( Negative acknowledgements ) 이다.

➡️ 이 경우에는 Sender가 다시 패킷을 보내준다.

 

여기에서도 위와 마찬가지로 아래와 같은 전제를 가지고 간다.

 


Sender와 Receiver 의 행동
기본적인 형태

 

Sender

1. 보내기

Application Layer에서 Transport Layer로 Data를 보낸다.

  ➡️ Transport Layer에는 Data와 Checksum을 포함한 패킷을 만든다.

  ➡️ udt_send를 통해 Receiver에게 패킷을 보낸다.

 

 

 

2. 정상적으로 받았다는 메시지 받기

Case1 )

다른 쪽에서 넘어온 데이터를 받았음 && 뜯어보니 제대로 못 받았다 (=NAK) 는 패킷

            ➡️ udt_send()로 필요한 패킷을 다시 보내준다.

 

 

Case2 )

다른 쪽에서 넘어온 데이터를 받았음 && 뜯어보니 제대로 받았다 (=ACK) 는 패킷

            ➡️ Action None

 


Receiver

- 받은 패킷 확인

 

case 1) Corrupt

Sender로 부터 패킷을 받음 && Corrupt 패킷임

            ➡️ udt_send로 NAK라는 걸 알려줌

 

 

case 2) No error( or no Corrupt)

Sender로 부터 패킷을 받음 && Non - Corrupt 패킷임

            ➡️ 패킷에서 데이터 추출

            ➡️ Application 계층으로 Data 전달

            ➡️ Sender에게 ACK 보냄

 

 

📌 한계점 

- ACK/NAK 에 Error가 생기면 답이 없다.

 

- 그냥 재전송하기에는 중복되는 데이터들이 쌓인다.

 

✅ 해결법

- ACK/NAK가 Corrupt 되었다면, 현재 패킷을 재전송한다.

- Sender가 패킷에 순번을 붙여서 보낸다.

- Receiver는 중복된 패킷을 버린다. (Application Layer로 보내지 않음)

 

이를 위해 Stop and wait 방법을 사용한다.

 


rdt 2.1

위에 2.0에서 구상한 해결법을 사용한다.

 

Sender

1. 보내기

 

Application Layer에서 Transport Layer로 Data를 보낸다.

  ➡️ Transport Layer에는 Data와 Checksum , 0번 flag 를 포함한 패킷을 만든다.

  ➡️ udt_send를 통해 Receiver에게 패킷을 보낸다.

 

 

2. 정상적으로 받았다는 메시지 받기

Case1 )

다른 쪽에서 넘어온 데이터를 받았음 && ( 뜯어보니 제대로 못 받았다 (=NAK) 는 패킷 or Corrupt )

            ➡️ udt_send()로 필요한 패킷을 다시 보내준다.

 

Case2 )

다른 쪽에서 넘어온 데이터를 받았음 && ( 뜯어보니 제대로 받았다  (=ACK) &&  Non- Corrupt )

            ➡️ Action None.

 

 

 

이번엔 flag를 1로 바꿔서 다시 주고받고함.

 


Receiver

- 받은 패킷 확인

 

case 1) Corrupt

Sender로 부터 패킷을 받음 && Corrupt 패킷임

            ➡️ udt_send로 NAK , Checksum을 담아서 잘못된 걸 알려줌

 

 

case 2) No error

Sender로 부터 패킷을 받음 && NonCorrupt 패킷임&& [ 패킷의 flag = 0 ]    ( 줄 때랑 받을 때 조건 하나씩 더 붙음 )   

            ➡️ Data를 Extract하고

            ➡️ Application Layer로 보낸다.

            ➡️ ACK 와 checksum을 담아서 보낸다.

 

 

📌 알아둘 것

- rdt 2.1 에서는 Flag 를 보고 한 번 더 판단을 거친다.

  > 이전 패킷/현재 패킷 중에 어느 패킷이 필요한지 판단하기 위함 

 

- Sender : Stop and Wait으로 작동하기 떄문에

                Flag는 0,1로 충분하다.

 

- Receiver : 받은 패킷이 중복되는 Packet인지 확인해야한다.

 

 

>> 근데 Receiver는 자신이 특정 패킷에 대해 보내는 ACK/NAK이

      Sender한테 도착했는지 확인은 어떻게 함?

 

 

 


rdt 2.2

NAC Free

+ 몇 번째 Packet에 대한 ACK를 준다.

따라서 NAC이 없어도

줬다고 말한 거랑 받았다고 말한 게 다르면 에러

 

⬇️흐름은 이거임

송신자 : 0번 보내유
> 수신자 : 0번 받음, 0번 받았어유
> 송신자 : 확인. 1번 보내유
> 수신자 : 1번 받음, 1번 받았어유
...

근데 에러가 나는 경우는 이거임
...
송신자 : 1번 보내유
> 수신자 : 0번 받았어유

 

 

Sender

0번 받았어~라고 와야 할 패킷에 

1번 받았어~라고 오면 에러임

 

2.1과 차이점을 잘 보자.


Receiver

0번 패킷을 받으면 [ 0번 + ACK + Checksum ]패킷을 만들어서 보낸다.

1번 패킷을 받으면 [ 1번 + ACK + Checksum ] 패킷을 만들어서 보낸다.

 

잘못됐는지 판단은 Sender에서 함

 


rdt 3.0

위에서 저렇게 해도 모자라다 싶었는지

최후의 수단을 씀

 

ACK를 '정해진 시간'동안만 기다림

해당 시간동안 ACK가 오지 않는다면, 다시 전송한다.

 

Sender

 

위에가 에러 없는 케이스

아래가 상세한 케이스

 

1. 보내기

- Application 에서 데이터 보냄

                 ➡️ 패킷 (0,데이터,chksum) 만든다.

                 ➡️ 보낸다.

                 ➡️ Start_timer

 

2. 정상적으로 받았다는 메시지 받기

case 1) 메시지를 받았음 , Corrupt이거나 1번으로 응답이 왔다

                 ➡️ 아무것도 안 함 (= Timeout 시켜서 다시 받으려고)

 

case 2) Timeout발생 

                 ➡️ 다시 보낸다

                 ➡️ Start_timer

 

case 3) 메시지를 잘 받았고 && Non-Corrupt && 0에 대해 ACK 가 왔다.

                 ➡️ 타이머 멈춘다. 

 

그 뒤엔 다시 패킷 seq를 1로 바꿔서 똑같이 진행

 

 

 

 

 


요약

 

GPT야 고맙다

 

(출처)

한동대학교 고윤민교수님 - 컴퓨터 네트워크