TCP 프로토콜의 기능과 특징
전송 계층의 대표적인 프로토콜인 TCP는 신뢰할 수 있고 정확한 데이터를 전달하기 위해 연결형 통신을 사용하는 프로토콜이다.
TCP 프로토콜은 데이터를 패킷이라는 작은 조각으로 분할하고, 모든 패킷이 수신지에 제대로 도착했는지 확인하고(연결형 통신 방식), 수신한 데이터의 순서를 송신한 순서대로 패킷들을 재조립 함으로써 전체 데이터가 올바르게 전송되도록 한다.
TCP 프로토콜의 데이터 단위 - 패킷 분할과 조립
TCP 프로토콜에 따라 데이터를 분할한 후, TCP 헤더를 붙여 캡슐화 한 전송 계층의 패킷을 세그먼트라고 한다. TCP에서 데이터를 분할하는 단위를 MSS(Maximum Segment Size, 최대 세그먼트 길이)라고 하며 일반적으로 사용하는 MSS의 표준 크기는 1,460 바이트이다. 이렇게 분할된 데이터에 순서 번호(Sequence Number)을 부여하여 전송 과정에서 전송 순서가 바뀌더라도 수신지에서 원래의 데이터로 재조립할 수 있다.
분할된 데이터에 순서 번호와 송신지 포트 번호, 수신지 포트 번호 등의 정보가 담긴 TCP 헤더가 붙어 세그먼트가 만들어지고, 이 세그먼트가 인터넷 계층으로 전송된다.
TCP 통신 과정
TCP 통신은 데이터를 전송하기 전에 먼저 ① 상대방이 데이터를 수신할 수 있는지 여부를 확인하여 상대방과의 연결(Connection)을 확립한 후 통신을 시작한다. 이후로 ② 데이터를 전송하고, 데이터 전송이 끝나면 ③ TCP 연결을 해제한다.
TCP 통신은 이처럼 통신 전과, 통신 중에도 계속 상대방과 연락을 취함으로써 데이터 전송의 확실성을 높인다.
① 연결 확립
3-way handshake
보통 한 컴퓨터에는 여러 애플리케이션이 동시에 사용되며, 애플리케이션 간의 통신은 데이터 전송 한번으로 끝나는 것이 아니라 여러 데이터가 연속해서 전송된다. 이때 애플리케이션 마다 연속으로 전송되는 데이터를 일대일의 가상의 이동 통로를 연결하여 전송(연결 확립)함으로써 애플리케이션별로 데이터의 흐름을 관리할 수 있게 된다.
이러한 가상 통로의 연결 확립은 3-way handshake라고 하는 3단계 과정을 거쳐 확립된다.
① 먼저 송신 호스트는 수신 호스트에 연결 확립 허가를 받기 위한 요청을 보낸다. 이때 연결 요청은 데이터 없이 TCP헤더(연결 요청 코드 값인 SYS)만으로 된 커넥션 확립 요청 패킷을 보낸다.
② 송신 호스트가 보낸 요청을 받은 수신 호스트는 연결 확립을 허가한다는 응답을 하기 위해 응답 코드 ACK를 TCP 헤더에 담아 보낸다. 동시에 송신 호스트로부터도 데이터 전송 허가를 받기 위해 연결 확립 요청(SYN)을 함께 보낸다.
③ 수신 호스트의 요청을 받은 송신 호스트는 수신 호스트에게 데이터 전송을 허가한다는 응답으로 ACK코드를 보낸다.
이와 같이 데이터를 보내기 전에 패킷을 3번 교환하면서 통신 상대방과 연결을 확립하는 과정을 3-way handshake라고 부른다. 이 3-way handshake에 의한 연결 확립 과정에서 송신 호스트와 수신 호스트의 상호 합의 하에 MSS가 결정된다.
② 데이터 전송
3-way handshake로 송신 호스트와 수신 호스트 사이에 연결 확립이 되면, 데이터를 전송할 수 있는 연결 통로가 만들어지게 된다.
연결 확립 단계에서 두 호스트 간의 통신에 사용될 MSS는 1460바이트, 순서 번호의 초기 값은 0으로 결정된 경우이다. 송신 호스트가 수신 호스트에 보낼 데이터가 8000 바이트인 경우, 송신 호스트는 그림 4와 같이 6개의 패킷으로 데이터를 분할한다. 이때 패킷의 순서 번호는 초기값인 0부터 패킷의 크기(MSS)만큼 증가한 값이 할당된다. 따라서 첫번째 패킷의 순서번호는 0, 두번째 패킷의 순서번호는 1460, 세번째는 2920 …이 된다.
- 먼저 송신 호스트에서 순서 번호가 0인 첫번째 패킷(1460바이트)이 전송된다.
- 수신 호스트는 첫 번째 데이터 1460 바이트를 수신한다. 이후 송신 호스트가 보낸 데이터를 잘 받았다는 의미로 다음에 받을 데이터 번호 1460을 확인 응답 번호에 넣어 송신 호스트로 보낸다. 이때 확인 응답 번호로 어디까지 데이터를 수신했는지, 다음에 보낼 데이터가 무엇인지 알 수 있다.
- 수신 호스트로부터 확인 응답을 받은 송신 호스트는 다음 데이터인 순서 번호 1460의 패킷을 전송한다.
- 수신 호스트는 1460 바이트의 데이터를 수신하고 다음에 수신하고자 하는 데이터의 순서 번호인 2920을 확인 응답 번호에 넣어 전송한다.
- 데이터의 전송이 완료될 때까지 위의 과정을 반복한다.
데이터 전송 과정에 오류가 발생해 수신 호스트에 데이터가 도착하지 않는 경우, 수신 호스트는 확인 응답 번호를 반환하지 않는다. 송신 호스트는 수신 호스트의 확인 응답을 일정시간동안 기다리다가, 확인 응답이 오지 않을 경우 데이터를 재전송하여 데이터 전송의 신뢰성을 확보한다.
③ 연결 해제
데이터 전송이 완료된 후에는 연결을 끊기 위한 요청을 교환해야한다.
먼저 송신 호스트는 데이터를 다 보낸 후 수신 호스트로 연결 종료 요청(FIN)을 헤더에 담아 보낸다.
수신 호스트는 송신 호스트로 연결 종료 응답(ACK)를 반환하고, 동시에 수신 호스트는 송신 호스트에게 연결 종료 요청(FIN)을 보낸다.
송신 호스트는 수신 호스트로 연결 종료 응답(ACK)를 반환한다.
TCP State
(출처: https://smjeon.dev/etc/tcp-state/)
TCP Connection open
TCP에서 connection established가 되는 과정. (DATA 전송 이전까지의 부분)
TCP Connection close
TCP 커넥션 종료는 클라이언트와 서버 어느 쪽에서도 할 수 있기 때문에, 클라이언트와 서버로 나누지 않고 active close와 passive close로 나눈다.
- active close: TCP 연결 해제를 요청한 쪽. 트래픽을 전송(request)하고 정상적으로 전송되었으면 연결을 끊는 쪽
- passive close: TCP 연결 해제 요청을 받은 쪽. 트래픽을 받는 쪽
Active Close / Passive Close
- 클라이언트는 FIN을 전송하고 FIN-WAIT-1 상태로 전환
- 서버는 FIN을 수신하고 ACK를 전송. CLOSE-WAIT 상태로 전환
- 클라이언트는 FIN에 대한 ACK를 수신하고 FIN-WAIT-2 상태로 전환
- 프로세스로부터 passive close명령을 받으면 서버도 FIN을 전송. LAST-ACK 상태로 전환 (프로세스로부터 passive close 명령을 받고 FIN을 정상적으로 보내지 못하거나, passive close명령을 받지 못하면, server쪽은 영원히 CLOSE_WAIT상태로 기다리게 된다)
- 클라이언트는 FIN을 수신하면 ACK를 전송하고, TIME-WAIT상태로 전환 (active close쪽은 passive close로 부터 FIN을 수신하지 못하더라도 일정 시간이 지나면 TIME WAIT으로 바뀐다)
- TIME-WAIT 상태로 2MSL 동안 남아있는다.
- 타이머가 만료되면 클라이언트는 CLOSED상태가 된다.
- LAST-ACK 상태로 있다가 클라이언트로부터 온 마지막 ACK를 수신하면 CLOSED 상태가 된다.
CLOSE WAIT
FIN-WAIT는 일정 시간이 지나면 TIME-WAIT(재 사용이 가능한 상태)로 전환되고, 일정 시간이 지나면 CLOSED상태가 되어 커넥션이 닫힌다. 하지만 passive close 쪽에서 프로세스로부터 passive close 명령을 받지 못해 FIN을 전송하지 못하면 CLOSE WAIT는 포트를 계속 잡고있는 상태로 멈추게 된다(timeout도 없이 계속 해당 상태로 존재). 이러한 상태는 프로세스의 종료 또는 네트워크를 재시작하는 것이 아니면 제거가 불가능하다(그래서 애플리케이션의 정상종료가 필요하다).
TCP 흐름 제어
통신의 신뢰성을 확보하기 위해 패킷을 전송할 때 마다 확인응답을 거치면, 송신 호스트는 확인 응답이 돌아올 때까지의 시간 동안 아무 일도 하지 않고 기다려야 하기 때문에 전송 속도가 지연된다. 통신에서 신뢰성만큼 중요한 것이 통신 속도이기 때문에 TCP는 흐름제어(flow control)을 통해 전송 효율을 높이고 있다.
흐름 제어는 패킷 단위가 아닌 더 큰 단위로 확인 응답을 하는 방법으로 이루어진다. 즉 여러 패킷을 한꺼번에 연속해서 전송한 후 확인응답을 받음으로써 전송 효율을 높이는 것이다.
확인 응답을 기다리지 않고 송신할 수 있는 데이터의 크기를 윈도우 사이즈(window size)라고 한다. 즉 윈도우 사이즈는 데이터를 전송할 때 한번에 전송할 수 있는 전체 패킷의 크기를 의미한다. 이때 윈도우 사이즈는 수신 호스트가 한번에 받아낼 수 있는, 수신 가능한 버퍼*의 크기가 된다.
*버퍼(Buffer)은 컴퓨터 메모리 상에 위치하여 송수신하는 패킷을 일시적으로 저장하는 저장소를 의미한다.
윈도우 사이즈는 수신 호스트의 상황에 따라 수시로 변하기 때문에, 수신 호스트는 응답확인을 보낼 때 수신할 데이터 위치와 버퍼 사이즈를 함께 전달한다. 송신호스트는 응답 확인을 받고 윈도우 크기를 확인하여, 윈도우 사이즈에 맞춰 송신할 패킷의 양을 조절하며 데이터의 흐름을 제어한다.
(출처: https://better-together.tistory.com/140)
본 내용은 제가 네트워크 공부를하며 위 블로그를 참고해 정리한 내용이어서 스스로가 이해하기 쉽도록 말을 길게 풀어 쓴 구간이 많습니다. 위 블로그에서 깔끔하고 상세하게 설명을 잘 하고 있기 때문에 공부를하는 분들은 위 블로그로 확인해보시는것도 추천드립니다~
'네트워크' 카테고리의 다른 글
Ubuntu에 NFS 구성하기 (0) | 2023.08.17 |
---|---|
네트워크 소켓(포트) vs 유닉스 소켓 (0) | 2023.08.03 |
IP주소의 종류와 할당 방법 및 NAT (0) | 2023.04.22 |
IP주소와 서브넷 마스크 (0) | 2023.04.22 |
[OSI 7-Layer] 응용 계층 (0) | 2023.04.22 |