이 글은 개발자 문동욱 님의 블로그 글을 보고 기억에 남는 것을 제 나름대로 정리한 포스트 입니다. 무작정 외우고 따라 쓰는 것 보다 다 읽고 어디까지 이해했는지, 어떤 것들이 내 머릿속에 남아있는지 확인 하면서 공부 하는 것이 더 좋다고 (동생이 적극 추천한 공부법) 하여 글로 남겨 확인해보려 합니다.

TCP

  1. TCP는 트렌스포트 계층에서 사용하는 프로토콜이다.
  2. 헤더의 정보들로 정보를 안전하고 정확히 순서대로 전달해준다.
  3. 왜 개발이 되었나? 핵전쟁이 발발해도 끊기지 않는 네트워크를 만들기 위해 개발 되었다.
  4. 헤더에는 많은 정보가 있는데 그 중 시퀀스 넘버는 세그먼트를 순서대로 보낼 수 있게 숫자를 부여한다.
  5. 어드레스와 포트번호로 어디로 데이터를 보내야 하는지 식별한다.
  6. 윈도우 사이즈는 한 번에 얼마나 많은 데이터를 받을 수 있는지 알려주는 정보이다.
  7. 컨트롤 비트라는 정보도 헤더에 있는데 9개의 플레그가 있다.
  8. 체크섬이라는 오류 체크하는 영역도 헤더에 있다.

신뢰성 확보를 위한 길 핸드쉐이크

  1. 연결을 생성 하고 종료 하는 방법으로 핸드쉐이크라는 방법을 사용한다.
  2. 핸드쉐이크는 정보를 주고 받는 방법이다.
  3. TCP는 연결 지향의 특징을 가지고 있다.
  4. 패킷을 통해 동시다발 적으로 기기와 기기간의 연결을 한다. 그러면 어떻게 누가 보냈는지? 이 패킷이 몇번째로 온 패킷인지 구별하나? TCP는 연결 상태 로 구별한다.
  5. TCP가 연결을 만들 때 과정을 3Way Handshake라고 한다.
  6. TCP가 연결을 해제할 때 과정을 4Way Handshake라고 한다.

수신자와 요청자가 있다. 수신자는 받는 쪽, 요청자는 연결 요청을 보내는 쪽이다.

연결을 만드는 과정

  1. 요청자(클라이언트) 수신자(서버)가 있다. 수신자는 요청자가 연결 요청을 할 때까지 기다린다.
  2. 요청자가 시퀀스번호(예를 들어 100이라고 하자)를 생성해서 SYN 패킷에 담아 보낸다.
  3. 수신자는 이 100을 받고 여기다 1을 더한 승인번호(ACK)를 만들고 받은 시퀀스 번호와 함께 다시 요청자에게 보낸다. (이때 승인번호는 101 번이 된다.)
  4. 요청자는 시퀀스 번호(내가 보낸 100)와 승인번호(수신자가 100 + 1 한 101)가 1 차이가 나면 연결이 잘 되었다고 판단한다.
  5. 잘 받았다고 판단한 요청자는 수신자가 만든 승인번호에 + 1을 더한 (예시로는 102가 되겠다) 승인번호를 만들어 다시 보낸다.
  6. 수신자는 자기가 보낸 시퀀스 번호(101)과 요청자가 보낸 승인번호(102)가 1차이가 나면 잘 연결이 되었다고 생각해서 본격적인 통신을 시작한다.

연결을 종료하는 과정

  1. 요청자가(클라이언트) 끝낸다고 수신자(서버)에게 FIN 패킷 + 승인번호(예를 들어 100이라고 하면)를 보낸다. 보내야할 순서에 맞는 시퀀스 번호도 같이 보낸다.
  2. FIN 패킷과 승인번호를 같이 보내는 이유는 수신자가 다 보내지 못한 데이터를 끝까지 받기 위해서다. 전송 스트림은 닫고 수신 스트림만 열어두는 Half-Close 기법을 사용한다. (입은 닫고 귀는 열어둘게 할 말 있으면 해~)
  3. 이때 수신자는 못보낸 데이터를 다 보낸다. 그럼 요청자는 반만 열린 스트림으로 열심히 처리 하고 수신자의 FIN 패킷을 기다린다.
  4. 데이터 보내기를 끝낸 수신자는 받은 승인번호 + 1(예시로 101)을 해서 요청자에게 보낸다. (나 끝났어!)
  5. 자신이 보낸 승인번호랑 1 차이가 나면 더이상 받을 데이터가 없다는 것을 알고 나머지 반도 닫는다.
  6. 수신자도 종료할 준비를 하고 FIN 패킷 + 승인번호(101)를 다시 요청자에게 보낸다.
  7. 요청자가 FIN 패킷을 받으면 승인번호(101)에 1을 더한 승인번호(102)를 다시 수신자에게 보내준다.
  8. 위 과정을 지나면 연결은 끊긴다.

TCP의 전송 제어 방법

TCP는 통신을 위해 데이터를 제어한다. TCP의 흐름 제어, 오류 제어, 혼잡 제어에 대해 알아보자.

흐름 제어

흐름 제어는 윈도우라는 도구를 이용해서 제어한다. 3 Way Handshake 연결 시 서버와 클라이언트는 한 번에 처리 할 수 있는 데이터 양에 대해 알려준다. 이것을 윈도우 사이즈라고 한다. 윈도우 사이즈는 처음 연결(3 Way Handshake) 할 때 패킷 왕복 시간을 보고 정한다. (이 측정 값 말고도 여러 요인을 보고 정하겠지만 대표적으로 사용하는 값이다.) 이 측정된 상대의 윈도우 사이즈 만큼 밀면서 데이터를 보내는 방법을 슬라이딩 윈도우 라고 한다. 통신을 할 때 서로 계속해서 처리 할 수 있는 데이터 양을 업데이트 해서 보내준다. 그래서 연속적으로 데이터를 보낼 수 있어서 빠르다. 흐름 제어 방법에는 슬라이딩 윈도우 말고 다른 방법(Stop and Wait)도 있는데 슬라이딩 윈도우가 효율이 좋아 요새는 다 이 방법을 쓴다고 한다.

오류 제어

오류 제어 하는 방법에는 여러 방법이 있다. TCP는 ARQ(Automatic Repeat Request)-> 재전송 기반 오류 제어라는 것을 사용한다. 오류가 났다는 것을 승인 번호를 통해 알 수 있다. 오지 않았거나, 번호가 중복 되었거나. 중복이 생겼다고 바로 오류라고 하지 않고, 한 세번 정도 반복이 되었을 때 오류라고 추측한다. 가끔 클라이언트에서 타임 아웃이라는 오류가 날 때가 있는데 이 경우가 바로 오류가 났을 때다. 클라이언트는 승인 번호를 보냈는데 서버가 다시 보내지 않고 시간이 지나면 타임아웃 오류가 뜬다. 클라이언트나 서버가 보낸 데이터가 중간에 유실 되었을 때

오류 제어 방법 중에 슬라이딩 윈도우 방법과 잘 맞는 방법은 Go Back N 이라는 방법인데, 이 방법은 ACK를 통해 자신이 처리 할 수 있는 데이터 양을 알려주고 상대는 그만큼 보낸다. 근데 만약에 중간에 데이터 에러가 났으면 ACK로 오류가 발생 했음을 알려준다. 재밌는건 오류가 난 순서 이후의 데이터는 쿨하게 지워버리고 에러가 난 부분부터 다시 보내달라 하는 것이다.

Go Back N 방법 말고 다른 방식도 있다. Selective Repeat이라는 방식인데, 해석 그대로 선택적인 반복, 즉 선택적으로 데이터를 전송 한다. 만약에 중간에 데이터가 오류 났으면 오류난 데이터만 다시 보내는 방식으로 오류 제어를 한다. 앞서 말한 Go Back N 방식 보다 훨씬 효율적인 것 처럼 보이지만, 단점이 있다면 데이터가 차례대로 차곡 차곡 쌓이지 않는다는 점이다. 그래서 별도의 버퍼를 통해 재정렬 과정이 필요하다. 두 방식 중에서 어떤것이 효율적인 가를 따져 사용 하면 될 것 같다.

혼잡 제어

혼잡제어 방식은 기본적으로 AIMDSlow Start 두가지가 있다. 혼잡 제어를 하는 이유는 너무 당연하게도 오류 상황(네트워크 혼잡 붕괴)을 피하기 위해서 사용한다. 서버는 클라이언트가 보낸 윈도우 사이즈와 네트워크 상황을 고려해서 정한 혼잡 윈도우 사이즈 중에서 더 작은 값을 채택한다. 서버의 윈도우 사이즈 ≠ 서버의 혼잡 윈도우 사이즈 라는 얘기. 혼잡 제어를 할 때 사용 되는 윈도우는 혼잡 윈도우를 말한다. 통신을 하는 중에는 당연히 혼잡 윈도우 크기를 늘렸다가 줄였다가 하지만 맨 처음 통신을 시작 할때는 어떻게 측정을 하냐? 한 번 통신 할 때 보낼 수 있는 최대 단위에서 IP 헤더, 옵션과 TCP 헤더, 옵션을 뺀 순수 데이터 양을 가지고 측정을 한다 이 친구를 최대 세그먼트 사이즈 라고 한다.

AIMD

네트워크가 혼잡할 때 윈도우 사이즈를 0.5 곱해서 줄이고, 널널하다면 1 더해서 늘리는 방식이다. 단점은 네트워크 대역이 남아도 천천히 속도를 증가 시키기 때문에 제대로 된 속력을 내기까지 시간이 걸린다는 점이다.

Slow Start

이 방식은 윈도우 크기를 늘릴 때 지수적으로 늘렸다가 네트워크가 혼잡하다고 생각되면 크기를 1로 줄여버린다. 장점은 AIMD에 비해 늘어나는 속도가 빨라서 네트워크 대역을 잘 활용 할 수 있다는 점이다. ACK가 도착 할 때마다 윈도우 크기를 증가시키기 때문에 처음에는 느릴지 몰라도 많은 데이터를 받기 시작하면 빨라진다.

혼잡 제어 정책

위의 혼잡 제어 방식을 적절하게 섞어서 혼잡도를 제어하는 정책들이 많다. 정말 많지만 그 중에서 가장 대표적인 정책은 아래의 두가지다. 아래 두가지 정책들은 ACK가 3번 중복 되거나, 타임 아웃(데이터 유실, ACK 유실되는 경우)이 발생하면 혼잡하다고 느낀다. 혼잡하다고 느끼면 오류 제어 방식(Go Back N, 선택적 반복 등)을 통해 오류가 났다고 알려준다. 이때 클라이언트는 타임아웃 시간이 지나지 않아도 바로 데이터를 다시 전송 할 수있는데 이것을 빠른 재전송이라고 한다. 또 특정한 임계점(어떤 변화가 일어나기 직전 한계점, 이 지점을 혼잡 제어 정책에서 Slow Start Threshold라고 한다.)을 정하고 그걸 넘어서면 AIMD 방식으로 전환된다. 이 임계점은 통신 시작 전에 서버에서 자신의 혼잡 윈도우 절반 크기로 초기화 한다.

Tahoe

빠른 재전송 기법이 처음 도입 되었다. 임계점(ssthresh)에 도달하면 Slow Start방식에서 AIMD 방식으로 전환하고 오류가 감지되면 임계점을 혼잡 윈도우 절반 까지 수정하고, 혼잡 윈도우를 1로 낮춘다. 이 정책의 단점은 오류가 감지 되면 임계점과 혼잡 윈도우를 줄여버려서 다시 속도를 내기까지 시간이 걸린다는 것이다.

Reno

레노와 타호의 가장 큰 차이점은 레노 정책은 ACK 중복 오류와 타임아웃 오류를 구별한다는 것이다. 타호 정책의 단점을 보안하여 빠른 회복 기법을 추가했다. ACK 중복 오류가 발생하면 혼잡 윈도우 크기를 반으로 줄이고 임계점(sshthresh)을 같은 값으로 정한다. 후에 AIMD 방식을 써서 합증가를 하여 기존 속도로 빨리 회복한다. 1부터 다시 시작하는 타호 정책보다 원래 윈도우 사이즈에 빨리 도달한다고 하여 빠른 회복이라고 한다. 타임아웃일 경우 임계점(sshthresh)은 수정하지 않고, 타호 정책처럼 혼잡 윈도우를 1로 줄여버리고 1에서 Slow Start 기법을 사용하여 다시 늘려나간다.

reference