네트워크

[네트워크 기초] TCP

dev-ohdam 2024. 6. 14. 00:33

 이전 게시글을 통해 OSI 7계층과 TCP/IP Protocol Stack(= 4계층)에 관해 포스팅을 하는 시간을 가졌다.

이번 시간에는 TCP 프로토콜에 관해 깊게 알아보는 시간을 가질 것이다.

 

 UDP, TCP는 4 계층인 전송계층에서 정의된 프로토콜이다.

해당 계층의 주요 역할은 데이터를 목적지까지 전송하는 것이다. 그렇다면 TCP 프로토콜은 이 전송을 어떤 방식을 통해 데이터 전송을 진행하고, 어떤 특징을 가지는지 살펴보자.

신뢰성 있는 데이터 전송 - TCP

  TCP는 데이터 전송을 수행할 때, 안정성 &신뢰성이 있다는 특징을 가지는 프로토콜이다. 

 

 이때 신뢰성과 안정성을 보장받을 수 있도록한느 TCP의 특징이 무엇이냐? 라고하면 다음과 같다.

 

1. Connection - Oriented : TCP는 연결형 프로토콜이다.

 

2. 오류 제어 : 체크섬,  확인 - 응답 과정을 통해 데이터 손실 및 중복을 검출하고 재전송을 수행. 

 

3. 흐름/혼잡 제어 : 네트워크 혼잡성, 수신자의 상황에 따라 전송 흐름을 제어해, 데이터 손실 방지.

 

4. 순서 보장 : 시퀀스 번호 부여를 통한 전송된 데이터들의 순서를 보장하고, 이를 재조립해 복원할 수 있다.

 

 

여기서 연결형 프로토콜은 데이터를 전송하기 앞서 사전에 먼저 연결 설정 후 통신을 수행한다는 특징이 있다.

Connection-Oriented 

 

가상 회선 패킷 교환

 

 

 TCP를 공부하는 과정에서  "연결 설정이라는 것은 뭘까, 이 과정은 무엇을 위해 수행하는 걸까?" 라는 의문을 가질 수

있다.

 

 여기서 연결(Connection) 설정이란, 패킷 전송을 위한 가상 회선을 확보하는 것을 의미한다. 

가상 회선이라고 부르는 이유는, 물리적인 연결을 통해 정의된 회선이 아닌 논리적인 연결을 통해 정의된 회선을 의미하기 때문이다. 우리는 이 회선 안에 설정된 경로를 통해 데이터를 전송하게 된다. 

 

 이런 가상 회선을 통해 데이터를 교환하는 방식을 가상 회선 패킷 교환 방식이라고 한다.

이때, 전송되는 패킷에 대한 가상 회선을 동일하게 설정되며 송수신 순서를 보장받을 수 있다. 또한, 물리적인 연결이 아닌 논리적인 연결이기 때문에, 특정 회선에 문제가 발생한다 하더라도, 우회하는 것이 용이하기 때문에 안정성이 높다.

 

 그리고 이 방식은 할당된 회선에 관해 하나의 패킷이 독점적으로 사용하지 않는다는 특징이 있다.

 

 연결을 확보하는 과정 - 3 - Way HandShaking

 TCP 프로토콜은 연결을 확보하기 위해, 3 - Way HandShaking 방식을 사용한다. 

여기서 중요한 점은, 이는 단순이 연결을 확립하는 것 뿐만 아니라, TCP 헤더에 들어갈 여러 가지 값들을 결정(시퀀스 번호, 확인 응답 번호, 윈도우 크기, 제어비트 등)하는 과정이기도 하다.  

 

이때, 연결 요청을 받는 호스트를 서버, 연결 요청을 수행하는 호스트를 클라이언트라고 부른다.

 

3 - Way HandShaking은 각각의 호스트가 SYN 과 ACK 패킷을 총 3번의 절차를 걸처 교환하게 된다.

여기서 SYN(Synchronize)은 연결 요청을 의미한다. ACK(Acknowledgment)는 요청에 관한 확인 응답을 말한다.

3 Way HandShaking

 

1. 

서버는 언제든지, 클라이언트의 연결 요청을 받아야하므로 Stateful한 상태여야한다.

그리고 포트 번호를 열어 놓고, 연결 요청을 기다리는 Listen 상태에 있는다.

 

2. 

 클라이언트는 서버에게 연결을 요청하기 위해 SYN 패킷을 송신한다.

이때 해당 SYN 패킷에는 임의의 값으로 결정된 초기 시퀀스 번호(ISN)이 담겨있다.

그 외에도 클라이언트의 윈도우 크기, MSS 등의 값들이 담겨져 전송된다.

 

(해당 요소에 관해선 아래에 TCP 헤더를 설명하며 언급할 것이니 지금은 크게 신경쓰지 않아도 된다.) 

 

3.

 클라이언트의  SYN 패킷을 수신한 서버는 패킷에 담긴 정보를 확인 한 후,

정상적으로 처리가 완료되면 ACK 패킷을 전송한다. 이때 ACK 패킷에는 클라이언트의 ISN + 1을 한 값이 담긴다.

그리고 2번 과정과 마찬가지로 서버와 관련된 정보(ISN, MSS, 윈도우 크기 등)를 SYN 패킷을 통해 전송한다. 

 

4.

 클라이언트도 마찬가지로 전송받은 SYN 패킷의 정보를 확인하고, 이에 관한 확인 응답을 전송한다.

 

1 ~ 4번의 일련의 과정에 모두 수행되면 연결이 설립(Establish)된다.

 

TCP 헤더 - TCP 통신을 위해선 어떤 정보가 필요한가

 앞서 3 - Way HandShaking 과정에서 SYN , ACK 외에도 부가적인 정보를 주고 받음을 알 수 있었다.

그렇다면 이런 값들은 어디에 저장되고 왜 필요한 것일까?

 

  이전 게시글에서 캡슐화 과정에 관해 언급한 적이 있다. 

우리는 데이터를 수신할 때, 각 계층 별로 정의된 부가적인 정보들이 응용 프로그램으로부터 전달받은 데이터에 헤더와 트레일러 형태로 붙여나가게 된다. 

 

즉, 해당 정보들은 헤더의 형태로 저장되며, 이를 TCP 헤더라고 부른다. 

TCP 헤더는 전송계층에서 부착되는 TCP 통신을 수행함에 있어 필요한 부가적인 정보들의 집합체다.

 

이때 TCP 헤더 + 데이터 형태의 패킷 단위를 세그먼트(Segment)라고 한다. 

 

TCP 헤더를 한번 간단하게 한번 살펴보자.

Segment 와 TCP 헤더

 

1. Source/Destination Port : 수신지/목적지에 관한 포트 번호

 

2. Sequence Number (일련번호) : 32비트 크기의 값으로,  전송하는 데이터의 첫 번째 바이트 정보를 담고 있다.

(= 세그먼트의 시작 지점) 

이때 우리가 처음 연결을 확보하는 과정에서 주고 받았던 시퀀스 번호는 ISN이라고 해서 랜덤값으로 설정된다.

(예측 가능하지 못하게 하여, 세션을 가로채거나, 중간자 공격을 예방할 수 있다.)

 

Ex) 만약 ISN = 3000 이라고 가정했을 때, 내가 200바이트의 데이터를 전송한 후의 다음 시퀀스 넘버는 3200이 된다.

 

 이 시퀀스 넘버를 통해, 세그먼트의 전송 순서를 파악할 수 있고 오류 발생 시,  어느 세그먼트의 데이터를 재전송해야하는 지 알 수 있다.

 

3. Acknowledgement Number (확인번호) : 32비트 크기의 값으로, 다음으로 받기 원하는 세그먼트의 시작 바이트 정보를 담고 있다. 그렇기 때문에 시퀀스 번호의 + 1 된 값이 담긴다. 이 1 값이 반영됐는가 안됐는가를 통해, 데이터가 제대로 된 전송을 수행했는지 확인할 수 있다.

 

4. DO(Data Offset) : 세그먼트에서 TCP 헤더가 아닌 실질적인 데이터가 위치한 시작 바이트 지점에 관한 정보를 담고 있다. (=TCP 헤더 길이 정보)

 

5. RSV (예약 영역):  아무 정보도 담기지 않는 공간이라고 한다. (낭비 공간)

 

6. 코드 비트: 현재 세그먼트가 의미하는 것이 무엇인지에 관한 플래그들이 담겨져 있다. (연결 종료? ACK? 긴급 데이터?)

 

7. 체크섬: 오류를 검출하기 위한 값이 담긴다. 검출 결과를 기반으로 데이터 재전송 여부을 결정한다.

 

8. 긴급 포인터: 먼저 급하게 처리해야할 데이터의 포인터값이 담긴다.

 

9 윈도우 사이즈: 16비트 크기의 값으로, 한 번에 전송할 수 있는 데이터의 양을 의미하는 값이 담긴다.

(아래에서 더 자세하게 다룰 것임)

 

 

TCP 데이터 전송 과정

TCP 전송 과정 그림 자료 1
TCP 전송 과정 그림 2 출저:http://www2.ic.uff.br/~michael/kr1999/3-transport/3_05-segment.html

 

 

 위의 그림 중 그림 1은 TCP 데이터 전송 과정을 도형으로 표현한 것이다.

그림 2는 TCP 데이터 전송 과정을 시퀀스로 표현한 그림이다.

응용프로그램을 통해 전달받은 전송 데이터를 버퍼에 저장한다. 그리고 이 데이터에 TCP 헤더를 부착한 후 전송을 수행한다. 전송이 완료된 후, 다음으로 전송될 데이터가 있다면 이에 관한 정보를 ACK를 통해 받을 수 있다.

 

 여기서 핵심 포인트는 송신 버퍼에 저장된 데이터는 전송이 된다고 해서 바로 삭제되는 것이 아니라, ACK를 받을 때까지 

삭제되지 않는다. 이를 통해 우리가 수신 쪽에서 문제가 발생했을 경우 수신 버퍼에 남아있는 데이터를 통해 재전송이 가능해진다.

 

그런데 여기서 이런 의문점이 든다.

 안정성을 보장하는 것은 좋은데.. 데이터를 한 번 보낼때마다 매번 응답을 받게 된다면 네트워크의 효율성이 낮아지지 않을까? 이때 필요한 것이 윈도우 크기이다. 앞서 TCP 헤더의 정보 중 하나인 윈도우 크기 값을 통해 이 흐름을 제어할 수 있다.

 

 

데이터 전송 흐름/혼잡 제어 - 윈도우 크기와 Sliding Window 기법

 윈도우 크기란, 상대 버퍼가 수용할 수 있는 데이터의 양을 의미한다. 보통 많은 송신으로 인한 상대 수신 버퍼에 오버 플로우 발생을 방지해 데이터 손실 위험을 줄이기 위한 위한 용도도 있지만, 이 윈도우 크기를 우리가 동적으로 설정함에 따라, 응답 주기를 제어해 네트워크 효율성을 높일 수 있다.

 

 예를 들어 윈도우 크기로 4000을 설정했다고 하면,  4000 바이트만큼 송신이 이루어지기 전까진 확인 응답을 받지 않는다.

 

이렇게 윈도우 크기를 사용하면 수신자의 처리 능력에 따라, 혹은 네트워크 혼잡 상황에 따라 데이터 전송 속도를 제어하거나 네트워크 효율성을 높일 수도 있다.

 

이런 흐름을 제어할 때 슬라이딩 윈도우라는 흐름 제어 기법을 사용한다. 과정은 아래 그림과 같다.

 

 지금까지 TCP이 무엇인지, 그래서 해당 프로토콜이 어떻게 신뢰성 & 안정성 있는 데이터 전송을 보장하는 방법에 관해

알아보았다.

다음 게시글에는 이와 관련된 추가적인 개념인 MSS(Maximum Segment Size)와 MTU(Maximum Transmission Unit)에

관해 알아볼 것이다.