[kocw 이미정]11. Connection-oriented transport: TCP

이건회·2022년 1월 28일
0

네트워크

목록 보기
11/24
post-thumbnail

  • 위 사진과 같이 RTT가 추정되는데 이전 RTT는 시간이 지날수록 가중치가 줄어든다. 알파값은 보통 0.125로 추정한다. sample rtt는 굉장히 가변적이므로 estimated rtt에 더 가중치를 둔다.
  • 네트워크의 동적 상태를 반영해 safety margin을 두어 estimated rtt에 더해준다.

3.5 Connection-oriented transport: TCP

  • reliable한 데이터 전송을 위해서는 체크섬, ack, nack, 파이프라이닝, 시퀀스 넘버, 타이머가 필요하다. tcp는 cumulative acks를 사용한다. 또 하나의 요청에 대해 재전송이 있어도 하나의 타이머를 사용한다.
  • tcp는 에러 컨트롤과 플로우 컨트롤, 컨제스쳔 컨트롤이 밀접한 관계를 갖고 있다. 이를 고려하지 않은 채 reliable한 데이터 전송을 위한 tcp 컨트롤을 공부하겠다.

  • 센더의 프로토콜 계층에서 붙이는 헤더는 리시버측의 tcp가 받아보게 된다. tcp 센더와 리시버는 어느 방향 스트림이냐에 따라 클라이언트일수도 있고 서버일 수도 있다.
  • 센더에서 발생하는 이벤트는 총 3가지인데, 데이터가 어플리케이션 계층에서 내려올 수도 있고, 상대방이 나한테 보내는 ack이 네트워크 계층에 내려오거나, 타임아웃이 발생할 수 있다.
  • 센더는 앱에서 데이터를 내려보내면 세그먼트를 포장하고 헤더에 시퀀스 번호를 붙이고 체크섬을 계산한다. 만약 이 세그먼트가 현재 타이머가 실행되고 있지 않으면 타이머를 시작시킨다. 이 타이머는 내보낸 것 중 아직 ack을 못받은 것 중 가장 오래된 것에 대해 세팅(타이머를 시작)한다.
  • 이후 타임아웃이 발생되면 세그먼트를 재전송해준다. 새로 내보내면 타이머도 다시 시작한다.
  • 네트워크 계층에서 상대방이 보낸 ack이 들어오면 ack이 된 정보를 업데이트하고 ack되지 않은 세그먼트에 대해 타이머를 다시 세팅한다.

  • tcp 센더의 동작 사진이다. Tcp센더는 다음 번 내보낼 세그먼트의 시퀀스 번호인 NextSeqNum과 다음 번 ack를 받기를 기대하는 시퀀스 번호인 sendbase 두개의 변수를 유지한다.
  • 앱이 데이터를 내보내면 세그먼트로 만들어서 네트워크 계층에 내보낸다. 이때 세그먼트 헤더에 붙일 시퀀스 넘버가 NextSeqNum 이다. 그리고 체크섬을 붙이고 ip계층으로 내려보낸다. 그러고 다음 시퀀스 넘버를 업데이트한다. 현재 시퀀스 넘버에 데이터의 크기(바이트)를 더한 값이 다음 시퀀스 넘버다. 만약 타이머가 작동되고 있지 않다면 첫 세그먼트라는 뜻이므로 타이머를 실행한다.
  • 타임아웃이 발생하면 아직 ack을 받지 못한 세그먼트중 가장 오래된 것을 재전송하고 타이머를 재시작한다.
  • 네트워크 계층에서 ack이 들어오면 현재 sendbase보다 ack 값(y)이 클 경우 sendbase를 Y로 갱신한다. 즉 100일 때 120이 들어오면 119까지는 다 잘 받았고 120을 기다린다는 것이다. 샌드베이스가 갱신 되었는데 아직 내보냈는데 ack을 못받은 세그먼트가 있으면 타이머를 다시 시작한다. 그렇지 않으면 타이머를 중단시킨다.

  • 위는 tcp의 재전송 과정이다. 호스트 a에서 b로 가는 경우다. 센더인 a는 앱에서 데이터를 받아 세그먼트를 만들어 b로 보낸다. 이 데이터는 시퀀스 넘버가 92고 크기가 8바이트다. 그럼 다음 시퀀스 넘버는 100이 된다. b에서 세그먼트를 받고 100이라는 ack을 내보낸다. 시작 바이트가 92고 거기에 8바이트 데이터가 페이로드에 들어갔으므로 99까지 잘 받았고 100을 기다린다는 뜻이다.
    -다음은 호스트가 첫 세그먼트를 내보내고, 연달아 두 번째 세그먼트를 시퀀스 100에 20바이트짜리로 보낸다. 이러면 두 개의 ack이 오는데 ack이 도착하기 전 타임아웃이 발생했다. 이 경우 타임아웃을 발생시킨 더 오래된 세그먼트(첫 세그먼트)를 재전송한다. b는 중복된 것을 받았으므로 재전송 데이터를 버리고 ack만 보낸다. ack이 120으로 나가는데 이는 cumulative이므로 아까 119까지 잘 받았으니 120을 보낸 것이다.
  • tcp에 세그먼트를 연달아 내보냈는데 첫 번째 ack이 없어질 수 있다. 그러나 두 번째 ack만 잘 도착하면 cumulative이므로 데이터가 잘 간 것을 확인할 수 있다.

  • tcp가 신뢰 있는 데이터를 전송하기 위해 엔드 호스트에 있는 센더와 리시버가 협력을 한다. 리시버 측에서 일어날 수 있는 이벤트가 있다.
  • 네트워크 측에서 세그먼트가 배송되는데 in-order일때와 out of order일 때가 있다. 순차적일 때는 n까지 시퀀스 번호를 받은 다음 그 다음 시퀀스 번호가 n+1이면 순차적인 것인데, 이 경우 받고서 아직 ack을 보낸 것이 하나도 없으면 최대 500ms까지 기다린다. 세그먼트가 연속적으로 도착하는데 ack을 내보낼 때 축적하여 최적으로 내보내기 위해서다. 그런데 내보낼 것이 있으면 즉시 붙여 보낸다.
  • 그런데 n까지 시퀀스 번호를 받은 다음 n+200이 올 경우 out of order이다. 이 때는 바로 ack을 보낸다. 그런데 이 때 아까 보냈던 ack을 또 보내면서 n+1을 받고 싶다고 말한다. 이때 보내는 ack을 duplicate ack이라 한다.
  • 그 다음 기대하는 세그먼트가 오면 아까 발생한 시퀀스 번호와의 갭을 채우는 세그먼트므로 딜레이 없이 바로 ack을 보내준다.

  • 타임아웃 인터벌은 일반적으로 길다. 따라서 loss가 발생하고 재전송이 되기까지 상당한 시간이 걸리는데, 이를 위해 duplicate ack이 계속 들어오면 타임아웃 전에 재전송을 한다. 이를 tcp fast retransmit이라 한다. 이는 tcp가 파이프라이닝을 하므로 세그먼트를 연속적으로 내보내는데, 중간에 하나가 없어지면 갭이 생기고 연달아 들어온다. 그 갭을 채우기 위해 duplicate ack을 보낸다. 그것을 세 번 받으면 tcp가 손실을 파악하고 재전송을 한다. 세 번은 기다려야 문제를 인식하기 때문이다.

  • 위 사진이 그 예시다. 센더가 파이프라이닝으로 세그먼트를 연달아 내보내고 하나가 손실된다. 리시버가 100의 ack을 보내는데 그 다음 것이 없어져 100을 또 보낸다. 이를 세 번 보내면 센더가 손실을 인지하고 100의 시퀀스 넘버 세그먼트를 보낸다.

3.5.3 flow control

  • flow 컨트롤은 리시버 측에서 일어난다. 센더의 tcp가 보낸 세그먼트가 네트웍을 통해 링크계층으로 들어온다. 링크를 잘 건너왔는지 확인하고 헤더를 제거 후 네트워크 계층에 보낸다. 네트워크 계충은 ip주소로 잘 도착했는지 확인하고 ip주소 제거 후 세그먼트를 tcp에 올린다. tcp는 세그먼트를 소켓을 위해 할당된 버퍼에 저장한다. 보내는 tcp 세그먼트를 보내는 속도가 위 계층에서 뽑아내는 속도보다 빠르면, 소켓을 위해 할당된 버퍼가 차게 된다. 버퍼가 찬 이후 도착한 세그먼트가 드랍되는 것을 방지하기 위한 것이 flow control이다.

  • 소켓이 만들어질때 운영체제가 소켓을 위한 버퍼를 할당해준다(RcvBUffer). rwnd는 사용 가능한 버퍼 공간의 양을 의미하는데, 센더는 in-flight 상태인 데이터의 양이 절대로 rwnd를 넘지 않게 해야 한다. 이것이 flow 컨트롤이다.
  • 플로우 컨트롤을 위해 리시버는 항상 rwnd 정보를 센더 쪽으로 내보내는 세그먼트에 마킹해서 보낸다. 이는 나에게 돌아오는 스트림을 위한 정보이다.

3.5.4 connection management

  • tcp는 데이터를 주고 받기 전 핸드셰이킹을 통해 커넥션을 셋업한다. 이 커넥션 셋업을 통해서 여러가지 파라미터를 negotiate하는데, 이는 시퀀스 번호를 무엇으로 할 것인지, 리시브 버퍼 사이즈는 몇인지 등이다.

  • tcp는 커넥션을 셋업할 때 3-way handshake를 한다. 사람의 경우 2웨이면 되지만 tcp의 경우 문제가 발생할 수 있다.

  • 왜냐하면 다음 사진이 그 시나리오다. 클라이언트가 연결 요청을 하고 서버가 받아들인다. 이후 데이터 교환을 하고 어느 시점에서 커넥션이 닫힌다. 이후 서버는 클라이언트와의 커넥션 내용을 모두 잊는데 만약 클라이언트가 재전송한 세그먼트가 커넥션이 닫힌 후 도착할 수 있다. 이 때 서버는 이를 새로운 커넥션 요청이라 생각하고 establish상태로 들어간다. 이 때 서버는 이에 대해 대답을 하지만 클라이언트는 묵묵부답이고 가비지 데이터가 발생할 수 있다.

  • 그래서 tcp가 3-way 핸드셰이킹을 한다. 클라이언트가 요청을 보내고 서버가 요청을 받아들이는 답변을 보낸다. 그러나 establish상태로 들어가지 않고 기다리다가 클라이언트로부터 그에 대한 ack이 오면, 클라이언트가 alived인 것에 대한 확신을 갖고 establish상태로 들어가게 된다.

profile
하마드

0개의 댓글