TCP(Transmission Control Protocol)
Today Keys : protocol, 계층, service, port, 포트, 서비스, TCP
본 포스팅은 'IT 엔지니어를 위한 네트워크 입문' [길벗] 서적에 포함된 '3. 네트워크 통신하기'의 내용 3.4.2장의 내용입니다.
TCP
TCP는 3.4.1 4계층 프로토콜(TCP, UDP)과 서비스 포트 절에서 간단히 다루었던 4계층의 특징을 대부분 포함하고 있습니다.
TCP 프로토콜은 신뢰할 수 없는 공용망에서도 정보유실 없는 통신을 보장하기 위해 세션을 안전하게 연결하고 데이터를 분할하고 분할된 패킷이 잘 전송되었는지 확인하는 기능이 있습니다.
패킷에 번호(Sequence Number)를 부여하고 잘 전송되었는지에 대해 응답(Acknowledge Number)합니다. 또한, 한꺼번에 얼마나 보내야 수신자가 잘 받아 처리할 수 있는지 전송 크기(Window Size)까지 고려해 통신합니다.
TCP의 여러 역할 덕분에 네트워크 상태를 심각하게 고려하지 않고 특별한 개발 없이도 쉽고 안전하게 네트워크를 사용할 수 있습니다.
패킷 순서, 응답 번호
TCP에서는 분할된 패킷을 잘 분할하고 수신 측이 잘 조합하도록 패킷에 순서를 주고 응답 번호를 부여합니다.
패킷에 순서를 부여하는 것을 시퀀스 번호, 응답 번호를 부여하는 것을 ACK 번호라고 부릅니다.
두 번호가 상호작용해 순서가 바뀌거나 중간에 패킷이 손실된 것을 파악할 수 있습니다.
보내는 쪽에서 패킷에 번호를 부여하고 받는 쪽은 이 번호의 순서가 맞는지 확인합니다.
받은 패킷 번호가 맞으면 응답을 주는데 이때 다음 번호의 패킷을 요청합니다.
이 숫자를 ACK 번호라고 부릅니다. 송신 측이 1번 패킷을 보냈는데 수신 측이 이 패킷을 잘 받는다면 1번을 잘 받았으니 다음에는 2번을 달라는 표시로 ACK 번호 2를 줍니다.
위 그림을 단계별로 설명하면 다음과 같습니다.
1. 출발지에서 시퀀스 번호를 0으로 보냅니다(SEQ = 0).
2. 수신 측에서는 0번 패킷을 잘 받았다는 표시로 응답 번호(ACK)에 1을 적어 응답합니다. 이때 수신 측에서는 자신이 처음 보내는 패킷이므로 자신의 패킷에 시퀀스 번호 0을 부여 합니다.
3. 이 패킷을 받은 송신 측은 시퀀스 번호를 1로(수신 측이 ACK 번호로 1번 패킷을 달라고 요청했으므로), ACK 번호는 상대방의 0번 시퀀스를 잘 받았다는 의미로 시퀀스 번호를 1로 부여해 다시 송신합니다.
윈도 사이즈와 슬라이딩 윈도
TCP는 일방적으로 패킷을 보내는 것이 아니라 상대방이 얼마나 잘 받았는지 확인하기 위해 ACK 번호를 확인하고 다음 패킷을 전송합니다.
패킷이 잘 전송되었는지 확인하기 위해 별도 패킷을 받는 것 자체가 통신 시간을 늘리지만 송신자와 수신자가 먼 거리에 떨어져 있으면 왕복 지연시간 (Round Trip Time, RTT)이 늘어나므로 응답을 기다리는 시간이 더 길어집니다.
작은 패킷을 하나 보내고 응답을 받아야만 하나를 더 보낼 수 있다면 모든 데이터를 전송하는 데 긴 시간이 걸릴 것 입니다. 그래서 데이터를 보낼 때 패킷을 하나만 보내는 것이 아니라 많은 패킷을 한꺼번에 보내고 응답을 하나만 받습니다. 가능하면 최대한 많은 패킷을 한꺼번에 보내는 것이 효율적이지만 네 트워크 상태가 안 좋으면 패킷 유실 가능성이 커지므로 적절한 송신량을 결정해야 하는데 한 번에 데이터를 받을 수 있는 데이터 크기를 윈도 사이즈라고 하고 네트워크 상황에 따라 이 윈도 사이 즈를 조절하는 것을 슬라이딩 윈도라고 합니다.
TCP 헤더에서 윈도 사이즈로 표현할 수 있는 최대 크기는 216입니다.
실제로 64K만큼 윈도 사이즈를 가질 수 있지만 이 사이즈는 회선의 안정성이 높아지고 고속화되는 현대 네트워크에서는 너 무 작은 숫자입니다.
점점 고속화, 안정화되는 환경에 적응하기 위해 윈도 사이즈를 64K보다 대폭 늘려 통신하는데 TCP 헤더는 변경이 불가능하므로 헤더 사이즈를 늘리지 않고 뒤의 숫자를 무시하는 방법으로 윈도 사이즈를 증가시켜 통신합니다.
이런 방법을 사용하면 기존 숫자에 10배, 100배로 윈도 사이즈가 커집니다.
TCP는 데이터에 유실이 발생하면 윈도 사이즈를 절반으로 떨어뜨리고 정상적인 통신이 되는 경우, 서서히 하나씩 늘립니다.
네트워크에 경합이 발생해 패킷 드롭이 생기면 작아진 윈도 사이즈로 인해 데이터 통신 속도가 느려져 회선을 제대로 사용하지 못하는 상황이 발생할 수 있습니다.
이런 경우, 경합을 피하기 위해 회선 속도를 증가시키거나 경합을 임시로 피하게 할 수 있는, 버퍼가 큰 네트워크 장비를 사용하거나 TCP 최적화 솔루션을 사용해 이런 문제들을 해결할 수 있습니다.
3방향 핸드셰이크
TCP에서는 유실없는 안전한 통신을 위해 통신 시작 전, 사전 연결작업을 진행합니다.
목적지가 데이터를 받을 준비가 안 된 상황에서 데이터를 일방적으로 전송하면 목적지에서는 데이터를 정상적으로 처리할 수 없어 데이터가 버려집니다.
TCP 프로토콜은 이런 상황을 만들지 않기 위해 통신 전, 데이터를 안전하게 보내고 받을 수 있는지 미리 확인하는 작업을 거칩니다.
패킷 네트워크에서는 동시에 많은 상대방과 통신하므로 정확한 통신을 위해서는 통신 전, 각 통신에 필요한 리소스를 미리 확보하는 작업이 중요합니다.
TCP에서는 3번의 패킷을 주고받으면서 통신을 서로 준비하므로 ‘3방향 핸드셰이크’라고 부릅니다.
TCP는 이런 3방향 핸드쉐이크 진행 상황에 따라 상태(State) 정보를 부르는 이름이 다릅니다.
서버에서는 서비스를 제공하기 위해 클라이언트의 접속을 받아들일 수 있는 LISTEN 상태로 대기 합니다.
클라이언트에서 통신을 시도할 때 Syn 패킷을 보내는데 클라이언트에서는 이 상태를 SYN-SENT라고 부릅니다.
클라이언트의 Syn을 받은 서버는 SYN-RECEIVE 상태로 변경되고 Syn, Ack로 응답합니다.
이 응답을 받은 클라이언트는 ESTABLISHED 상태로 변경하고 그에 대한 응답을 서버로 다시 보냅니다.
서버에서도 클라이언트의 이 응답을 받고 ESTABLISHED 상태로 변경됩니다.
ESTABLISHED 상태는 서버와 클라이언트 간의 연결이 성공적으로 완료되었음을 나타냅니다.
3방향 핸드셰이크 과정이 생기다보니 기존 통신과 새로운 통신을 구분해야 합니다.
어떤 패킷이 새로운 연결 시도이고 기존 통신에 대한 응답인지 구분하기 위해 헤더에 플래그(Flag)라는 값을 넣어 통신합니다.
TCP 플래그는 총 6가지가 있고 통신의 성질을 나타냅니다.
초기 연결, 응답, 정상 종료, 비정상 종료 등의 용도로 사용됩니다.
● SYN
- 연결 시작 용도로 사용합니다. 연결이 시작될 때 SYN 플래그에 1로 표시해 보냅니다.
● ACK
- ACK 번호가 유효할 경우, 1로 표시해 보냅니다.
- 초기 SYN이 아닌 모든 패킷은 기존 메시지에 대한 응답이므로 ACK 플래그가 1로 표기됩니다.
● FIN
- 연결 종료 시 1로 표시됩니다. 데이터 전송을 마친 후 정상적으로 양방향 종료 시 사용됩니다.
● RST
- 연결 종료 시 1로 표시됩니다. 연결 강제 종료를 위해 연결을 일방적으로 끊을 때 사용됩니다.
● URG
- 긴급 데이터인 경우, 1로 표시해 보냅니다.
● PSH
- 서버 측에서 전송할 데이터가 없거나 데이터를 버퍼링 없이 응용 프로그램으로 즉시 전달할 것을 지시할 때 사용됩니다.
통신을 처음 시도할 때 송신자는 플래그에 있는 SYN 필드를 1로 표기해 패킷을 보냅니다.
이때 자신이 사용할 첫 seq no(시퀀스 번호)를 적어 보냅니다.
이 SYN 패킷을 받은 수신자는 SYN과 ACK 비트를 플래그에 1로 표기해 응답합니다.
자신이 보내는 첫 패킷이므로 SYN을 1로 표기하고 기존 송신자가 보냈던 패킷의 응답이기도 하므로 ACK 비트도 함께 1로 표기합니다. 이 패킷은 송신자의 연결 시도를 허락하는 의미로 사용됩니다.
이 때 자신이 사용할 시퀀스 번호를 적 고 ACK 번호는 송신자가 보낸 시퀀스 번호에 1을 추가한 값을 넣어 응답합니다. ACK 번호는 10 번까지 잘 받았으니 다음에는 10+1번을 달라는 의미입니다.
수신자의 응답을 받은 송신자는 연결을 확립하기 위해 다시 한 번 응답 메시지를 보냅니다.
이 때부터는 기존 메시지의 응답이므로 ACK 필드만 1로 표기됩니다.
수신자가 ACK 번호를 11로 표기해 보냈으므로 시퀀스 번호를 11로 표기해 응답합니다.
동시에 수신자의 시퀀스 번호 20에 대한 응답이므로 ACK 번호를 21로 보냅니다(20번을 잘 받았으니 다음 시퀀스 번호를 보내달라)