-Connection-oriented Transport : TCP

박솔찬·2022년 1월 8일
0

Network

목록 보기
2/2
post-thumbnail

TCP - Overview

  • RFCs : 793, 1122, 1323, 2018, 2581의 표준이 있다.
  • point to point로 이동한다. 즉, 송신기 - 수신기 하나씩 짝을 이룬다.
  • reliable를 제공한다. 즉, 신뢰성 있는 데이터 서비스를 상위층에 제공한다.
  • 전달받은 데이터의 순서를 맞추어 상위층에 제공한다.
  • TCP의 패킷은 Segment라 부르며 TCP는 데이터를 바이트 스트림으로 본다. 즉, 전송해야 할 데이터를 순서대로 정렬 된 바이트 스트림으로 취급한다.
  • pipelined protocols(슬라이딩 윈도우)의 두 가지 방법을 섞어서 사용한다.
  • 혼잡 제어(congestion) 및 흐름 제어(flow control)를 제공하며 이를 통 윈도우 사이즈를 정한다.
  • full duplex : 동일한 커넥션에서 양방향 통신이 가능하다.
  • MSS(Maxmin segment size)를 지정한다.
  • connection-oriented : 연결 설정(handshaking, control msg를 상호 교환, 센더와 리시버의 상태 정보를 초기화) -> 데이터 교환 -> 연결 해제

TCP Segment Structure

  • sequence number가 있다는 것은 신뢰성을 제공한다고 볼 수 있다.
  • sequence number와 ack num는 바이트 단위로 표시된다.
  • head Len : 옵션의 길이가 가변적이기 때문에 헤드의 길이를 표시하여 헤더가 어디까지인지 표시한다.
  • Not used : 현재 사용 X, 연구 또는 추후 이용하기 위해 예약해놓은 필드
  • U(URG) : 비트, 긴급 데이터가 담겨 있는지를 Set하는 부분
  • A(ACK) : ACK 넘버가 있다면 Set표시
  • P(PSH, push) : 다른 세그먼트가 올 때 까지 기다리지 말고 받으면 바로 올리라는 Set 부분
  • R(RST) : 리셋
  • S(SYN) : 셋업, Hand Shaking같은 연결 설정 단계에서 사용된다.
  • F(FIN) : 연결 해제 단계에서 설정된다.
  • receive window : 리시버가 한 번에 수용할 수 있는 윈도우 사이즈를 지정, 제한 하는 필드
  • checksum : UDP와 동일, 데이터의 변경 및 에러를 확인하기 위한 필드, Cheksum 계산
  • URG data pointer : U가 Set 되어있을 때 긴급 데이터가 위치한 주소를 저장
  • options
  • application : 가변적인 길이의 데이터를 갖는 필드.

TCP Sequence & ACK

  • Sequence number : 세그먼트에 대한 구분을 위한 값 이며, 바이트 스트림으로 나타내기 때문에 각 세그먼트들의 첫 번째 바이트를 seqnum으로 한다.
  • ACK(acknowledgement) : 패킷을 정상 수신한 뒤 응답할 때 지정되는 값 이며 받은 Sequence num 기준으로 결정된다. 기존에는 1, 2, 3을 정상수신하면 3을 ACK로 보냈지만 TCP에서는 3이 아닌 3 + data 크기를 보낸다. 즉, Seq num이 3이고 Data가 'C'이면 응답 ACK는 4이다.
  • GBN방식의 Cumulative ACK방식을 이용한다. 즉 3을 받았다고 보내면 1, 2, 3 모두 정상 수신을 뜻한다.
  • 2가 오기전 3이 도착한 상황 즉, out-of-order이 나타나면 처리하는 방법의 표준을 제공하지 않고 구현자가 직접 다룬다.
    TCP의 Sequence num와 ACK는 아래에서 자세한 예시로 알아보자.

TCP Reliable Data Transfer

  • IP는 unreliable하다 즉, 하위층에서 신뢰성 없는 데이터가 올라올 수 있고 TCP가 신뢰성을 지원한다.
  • 파이프라인 세그먼트를 사용한다.(pipelined protocols의 두 가지 방식을 혼합하여 사용)
  • GBN방식의 Cumulative ACKs를 약간 변형하여 사용한다.
  • 가장 오래된 세그먼트에 대한 타이머 하나만 운용한다.
  • 재전송은 타임아웃 또는 중복 ACK가 송신기에 오면 한다.

기본적인 TCP 통신 방식

[##Image|kage@9QFRA/btrp96Hr9qA/w2pKTii9K1F2tFCW5K3kOK/img.png|CDM|1.3|{"originWidth":266,"originHeight":292,"style":"alignCenter"}##]

A가 B에게 Seq를 42, ACK를 79로 세팅하고 1byte의 크기를 갖는 데이터를 보낸다.
B는 Seq를 전달 받은 ACK로 세팅하고 ACK는 전달 받은 Seq에 데이터 크기만큼 더한 값을 세팅한다.
이렇게 Seq와 ACK가 세팅된다.

신뢰성 제공

A가 B에게 보낸 요청이 중간에 유실되면 어떡하지?
B가 A의 요청을 수신하고 응답을 보냈는데 이것도 유실되면 어떡하지?
이런 부분에서 신뢰성을 다음과 같이 제공한다.

1. B의 응답이 유실된 경우
TCP는 타이머를 작동시켜 보낸 요청에 대한 응답이 일정시간안에 오지 않으면 재요청을 한다.

[##Image|kage@5NzuD/btrp5AwJVtz/S8y9ezsNbKdHLwQfdJD5W1/img.png|CDM|1.3|{"originWidth":243,"originHeight":353,"style":"alignCenter","caption":"B의 응답이 유실"}##]

위 그림처럼 B가 보낸 응답이 유실되었고, timeout이 발생하였기 때문에 A는 동일한 요청을 다시 보낸다.

2. A는 2개의 요청을 보냈고, 아무런 응답 없이 Timeout이 발생한 경우

[##Image|kage@tZ3EN/btrp3Wz28Jj/se2kKOZkFRWRFuftOqGHa0/img.png|CDM|1.3|{"originWidth":240,"originHeight":349,"style":"alignCenter","caption":"Timeout"}##]

위 그림은 A가 2개의 요청을 보냈고, B는 Timeout이 발생한 뒤 각 요청에 대한 응답을 하였다.
TCP는 가장 오래된 세그먼트 하나에만 타이머를 운용한다.
따라서 1번(Seq 92) 요청이 Timeout되면 다시 1번을(Seq 92) 요청한다.
그런데 B는 응답이 유실된 것이 아니고 1번, 2번 요청이 모두 정상 처리 된 상태이다.
따라서 1번을 재요청 받으면 1번과 2번의 응답을 각각 보내는 것이 아닌, 2번 응답(ACK 120) 하나면 보내어 통합적으로 처리한다. 그러면 A는 1번에 대한 응답은 받지 못 했지만, 2번에 대한 응답을 받았기 때문에 1번과 2번 모두 정상 처리로 반영한다. 이러한 방식을 Cumulative ACKs이라고 한다.

여기서 Cumulative ACKs에 대해 좀 더 다루어 보자.
A가 1번 요청을 보내고 B는 정상 처리 했다고 가정하자.
그러면 B는 이에대해 바로 ACK를 응답하는 것이 아니라 500ms대기한다.
만약, 대기중 순서에 맞는 세그먼트(+ 순서에 맞는 Seq)가 오면 처리 후 2개를 응답하는 것이 아니라 이에 대한 ACK만 응답하여 통합적으로 처리한다.

3. A는 여러 요청을 보냈고, 중간 요청이 유실된 경우

[##Image|kage@xLxiJ/btrp7R453Dl/g9ncfbWJMO6MPLXNijt3Q0/img.png|CDM|1.3|{"originWidth":264,"originHeight":385,"style":"alignCenter"}##]

  • 타임 아웃 기간이 긴 경우가 있을 수 있다.
  • Duplicate ACK(ACK 재전송)이 세 번 발생하면 loss가 발생했다고 인식
  • 송신기에서 1, 2, 3, 4 ,5를 보냈다고 가정(많은 부분을 이해할 수 있음 꼭 이해하기)
    • 2번에서 유실이 발생하여 3번이 왔을 때 3번에 대한 ACK를 넣어 보낼 수 없고 1번을 넣은 ACK 100을 보낸다.
    • 4번 요청이 왔지만 2가 안 왔기 때문에 ACK 100을 보낸다.
    • 5번 요청이 왔지만 2가 안 왔기 때문에 ACK 100 보낸다.

이렇게 세 번 동일한 Duplicate ACK가 발생하면 송신기는 loss발생했다고 인지하고 세그먼트를 재전송한다.
Fast Retransmit라 하는 것은 동일한 ACK재전송이 타임아웃 전 에 세 번(총 4번) 발생하여 송신기가 loss를 인지하고 세그먼트를 재전송 할 수 있기 때문이다.
3, 4, 5를 정상 수신하였고 재전송 받은 2번 세그먼트를 정상 수신하여 응답하는 ACK는 2번의 다음인 ACK 3이 아닌 ACK6을 보낸다. 왜? 5까지 정상 수신 하였기 때문이다.
즉, 그림에서 마지막으로 B가 응답할 ACK는 5번 요청에 대한 ACK인 것이다.

TCP Flow Control / 흐름 제어

  • 수신기 TCP가 어플레케이션 층으로 데이터를 버퍼로 올리는데 어플리케이션 층에서 수용하는 데이터 크기보다 올리는 양이 더 많으면 TCP Segment Payloads에 버퍼로 저장한다.
  • 버퍼가 꽉 차면 추가로 올라오는 데이터는 손실이 발생한다.
  • 이를 방지하기 위해 TCP는 flow control을 한다.

Flow Control

  • 수신기가 송신기를 제어한다.
  • 송신기 측에 수신기가 수용할 수 있는 양의 데이터를 보내도록 요청한다.
  • TCP Segment payloads는 사용중인 buffered data와 free buffer space 두 공간으로 나뉜다.
  • free buffer space의 크기(RcvBuffer)를 TCP header에 receive window(16bit)에 넣어 보낸다.
  • 송신기 측의 윈도우 사이즈는 RcvBuffer에 의해 변화된다.
  • 세그먼트를 받을때마다 receive window사이즈(RcvBuffer)는 변한다.
  • 기본 사이즈는 4096 bytes
  • 위 방법으로 흐름 제어를 보장한다.

연결 설정과 해제

데이터 교환 전에 송수신 측은 서로 HandShake 즉, 연결 설정(con setup or establish)을 한다.
데이터 교환이 끝나면 연결 해제를 한다.

연결 설정(3way-handshake)

[##Image|kage@pnBmf/btrp6QewDZB/EtkHY27PlNDibsrSkc6C30/img.png|CDM|1.3|{"originWidth":232,"originHeight":287,"style":"alignCenter"}##]

  • 클라이언트가 임의의 숫자(0 ~ 2^32 - 1) x를 지정하고 TCP 헤더 SYN부분을 1로 바꾸고 x값을 담아서 서버에 보낸다.
  • 클라이언트의 상태가 SYN SENT로 바뀐다.
  • 서버에서 수신하면 서버 상태가 SYN RCVD 바뀐다.
  • 서버에서 사용할 임의의 숫자(0 ~ 2^32 - 1) y를 지정하고 받은 요청에 대한 ACK를 보내는 데 SYN부분을 1로 바꾸고 y를 Seq로 설정하고 헤더 ACK부분을 1로 변경, ACKnum은 x+1로 하여 송신 측에 보낸다.
  • 클라이언트에서 응답받고 SYN이 1임을 확인하여 수신을 확인해달라는 의미로 인식
  • 헤더 ACK부분을 1로 하고 ACKnum은 y+1로 넏고, 서버로 보낼 데이터가 있다면 함께 보낸다. 이렇게 데이터를 함께 보내는 방법을 piggybacking이라고 한다.

연결 해제

클라이언트, 서버 각각 연결을 닫을 수 있다.
클라이언트에서 연결 해제 요청을 할 수도 있고, 만약 클라이언트에서 해제 요청을 했는데 아직 서버에서 보낼 데이터가 남아있는 경우라면 서버에서 해제 요청을 할 수도 있다.

[##Image|kage@6DpMp/btrp6Rds8mz/qJSq5FfUPuznB6hGjy0lj1/img.png|CDM|1.3|{"originWidth":642,"originHeight":386,"style":"alignCenter"}##]

  • 클라이언트가 (FINbit : 1, seq : x(랜덤, 초기값 아님))로 설정하여 서버에 해제 요청을 한다.
  • 클라이언트는 FIN_WAIT_1 상태로 변경된다.
  • 서버는 수신 후 CLOSE_WAIT 상태로 변경된다.
  • 서버는 아직 클라이언트로 보낼 데이터가 남아 있는 상태라(ACKbit : 1, ACKnum = x+1) FIN을 1로 설정하지 않고 ACK을 1로 설정하여 응답한다.
  • 클라이언트는 수신하고 Client FIN_WAIT_2 상태로 변경한다.
  • 서버에서 데이터를 모두 보내고 나면 서버는 FINbit : 1, seq : y(랜덤, 초기값 아님)로 설정하여 클라이언트로 보낸다.
  • 서버는 LAST_ACK 상태로 변경한다.
  • 클라이언트는 요청을 받은 뒤, ACKbit : 1, ACKnum : y + 1로 설정하여 서버에 보낸다.
  • Client는 TIMED_WAIT 상태로 변경된다.
  • 서버는 요청을 받으면 상태를 CLOSED로 변경한다.
  • 클아이언트는 서버에서 데이터가 모두 왔는지 모르기 때문에 segment 생존타임 * 2 동안 대기 후 서버에서 응답이 없으면 CLOSED 상태로 변경하고 연결이 해제된다.

만약, 연결 해제 과정 중 서버에서 응답할 데이터가 없는 경우에는 클라이언트의 FIN_WAIT2와 서버의 COLSE_WAIT단계는 생략된다.


자료 출처

All material copyright 1996-2016 J.F Kurose and K.W. Ross, All Rights Reserved

profile
Why? How? What?

0개의 댓글