socket programming
reliable하다는건 뭐냐>
app에서 내려온 메세지가 하나도 유실되지 않고 error 없이 다시 app으로 전달한다는 뜻이다.
하지만 unreliable 한 환경때문에 초래하는 결과가 있다.
=> 2가지 안좋은 일이 발생해
1) 패킷이 유실되거나
2) 패킷이 에러가 된다.
아주 간단한 reliable data transport protocol을 머리속으로 디자인 해보자.
한번에 패킷 하나 보낼 것이다 !
receiver가 잘 받았는지 100프로 확신이 들면 다음 패킷 보내고 이럴 것 !
가정 1. underlying channel이 reliable 할 때 !
우리가 할건 없다 !
가정 2. 만약 패킷 에러가 가능한 채널일 때!
우리가 어떤 메커니즘이 필요할까?
에러없이 메세지를 받게 하려면?
기본적으로, 에러를 판단해야 한다.
보내는 패킷의 checksum을 헤더에 담아가지고, 에러를 판단하게끔 한다.
만약, 리시버가 확인하는데, 에러가 있었다?
=> 피드백이 필요하다 (잘받았는지, 에러가 있었는지) 패킷을 받을 때마다
이 메커니즘으로,
모든 에러를 커버할 수 있는걸까?
=> 만약 피드백에 에러가 있는 경우에 !
처리가 확실하지 않음.
=> 그래서 센더가 또 보내
=> 리시버는 메세지가 두개와서 이게 한 묶음인지, 두개 온건지 헷갈림
결론
sequence number를 붙이는 가장 직관적인 방법은 ?
. 그냥 순서대로 0,1,2,3,4 붙이면 된다.
똑같은건 똑같은 번호 쓰고,,,
sequence 넘버는 어디에 들어가나?
패킷을 보면 데이터 부분이 있고, 헤더 부분이 있다.
header에 들어간다. header에 어떤 sequence 넘버
그럼 header에 시퀀스 넘버를 넣는 필드가 있다.
그럼 이게 무한정으로 커진다. 순서대로 0,1,2,3,4,... 계속 커진다면 !!
header 크기가 크면 안좋다.
시퀀스 넘버는 사실 2개만 있으면 된다. 0,1로만 구분하면 된다.
=> 1비트면 충분하다.
동작원리는 똑같은데
ACK, NACK가 복잡하게 느껴진다.
=> ACK만 사용하자!
=> ACK안에 들어가는 시퀀스 넘버가 가장 마지막으로 받은 시퀀스 넘버를 집어넣는다. !
가정) 에러뿐만 아니라, 메세지 유실도 가능한 경우
LOSS인 상황에 처리할 수 있게 메커니즘을 고치면 된다.
메세지 유실이 일어나면 어떠냐?
메세지 보냈는데 유실됐다? 센더 입장에서는 아무것도 안듣게 된다.
(저녁 같이 먹을래? 이게 유실됐음. 그냥 침묵이 흘러. 긴장감 고조. 누군가가 긴장감을 못견디고. 내 말 못들었어? 우리 맘속에 타이머가 있는거야.)
센더 입장에서 피드백을 못듣는다. 그럼 이 상황을 해결할 수 있는건 마음 속에 잇는 타이머가 해결해줘야 한다.
유실됐구나 생각하고 재전송하면 된다 !
타이머를 짧게 잡았다고 치자
=> 패킷을 딱 보낼 때 타이머를 틀고, 가서 제대로 들어오고 있는데 내가 재전송을 보내버렷어. 이 패킷을 리시버는 다시 버려야한다. 리시버는 잘 처리할거야 ㅇㅇ !
결국엔 unreliable 한 네트워크 때문에 일어나는 일이다. => 패킷 에러, 패킷 로스
=> 극복하기 위해 매커니즘을 집어넣어야 하는데,
=> 패킷 에러를 위해서
=> 패킷 로스를 위해서
결국엔 tcp는 reliable하니까 이런 매커니즘이 구현되어있다 !
헤더 부분에 정보 필드로서 담겨가야 한다.
피드백이니, 에러 디텍션이니 하는것들이 tcp 헤더에 필드로 구성되어있다고 ! tcp가 제공하는 기능이 reliable 뿐만 아니라 많잖아! 그러니까 헤더에 있는 필드들이 많을 수밖에 없고, 각각 의미가 있다!!!
지금까지 우리가 배운
RDT라는 프로토콜은 너무 단순하다.
한번에 하나의 패킷밖에 못보내. 패킷 보내고 , 확인하고 ~~~ 반복,,,
그림을 보면
SENDER가 패킷 보내고, 네트워크 사용을 아무것도 안한다. 기다리기만 한다.
그래서 실제로는 패킷을 안받고 쏟아붓는다. 한꺼번에 피드백 받는다.
=> 파이프라인 프로토콜
많은 것을 배웠습니다, 감사합니다.