TCP는 두 호스트 간의 유니캐스트(unicast) 연결 지향(connection-oriented) 프로토콜입니다. 따라서, 두 호스트가 데이터를 보내기 전에 상호 간의 연결을 해 주어야 합니다. TCP의 연결을 수행하기 위해서 각 호스트의 IP주소, Port번호로 구성된 4-tuple 데이터가 필요하며, 각각의 IP-PORT쌍은 TCP 소켓을 구성하는데 활용됩니다.
TCP Connection Overview
TCP를 사용한 통신은 설정, 데이터 전송, 연결 종료 3개의 단계를 거쳐서 수행됩니다. TCP/IP Illustrated에서 표현한 TCP Connection Diagram은 아래와 같습니다.
우선 해당 다이어그램에 대해서 알아보도록 하죠. 연결을 요청하고 연결 종료를 요청하게 될 주체를 Client(Active Opener)라 부르고, 그리고 그 연결의 상대방을 Server(Passive Opener)라고 합니다. Client가 연결 종료를 요청해야 하는 이유는 이후의 포스팅에서 다루도록 하겠습니다.
앞서 언급한 바와 같이, TCP 통신은 크게 세단계를 거치며 이루어집니다. 가장 먼저, Three-Way Handshake를 통해 각 호스트의 TCP 소켓이 상호 간에 연결될 준비가 되었는지 확인하는 과정을 거칩니다. 이후에는 생성된 소켓을 통해 데이터를 주고받고, Four-Way handshake를 통해 연결을 종료합니다. 각각에 단계에 대해서 자세히 알아보기 전에, 위의 다이어그램에서 각 라인에 적힌 TCP Header에 관련한 용어에 대해 알아보도록 합시다.
TCP Header & TCP Flags
현대의 네트워크에서는 계층화와 캡슐화를 활용한 추상화된 인터페이스를 통해 데이터를 전송합니다. 그중 전송계층에 해당하는 프로토콜인 TCP의 경우에도 캡슐화를 위해 TCP헤더라는 것을 사용합니다. TCP를 통해 전송되는 데이터의 단위를 TCP Segment라고 부르는데, TCP Segment는 TCP Header와 TCP Data로 구성되어 있습니다. 그중 TCP Header는 데이터의 목적지와 출발지 등의 정보를 담고 있고, TCP Data는 Client나 Server가 전송하고자 하는 데이터 그 자체입니다.
TCP헤더의 가장 앞에는 Segment의 출발지/도착지의 Port번호가 저장되어 있습니다. 왜 IP주소는 들어있지 않는가라고 생각할 수 있겠지만, IP주소에 대한 처리는 네트워크 계층에서 처리될 것이므로 TCP에서는 신경 쓸 필요가 없습니다.
다음 두개의 필드에는 Sequence(이하 SEQ) Number와 Acknowledgment(이하 ACK) Number가 저장되어 있습니다. Sequence Number는 어떤 호스트가 전송한 데이터의 순서를 나타냄과 동시에 어떤 TCP Segment를 식별하는데 쓰이는 숫자입니다. unsigned 32bit 정수 값을 가지며 이는 ACK Number의 경우에도 동일합니다. Acknowledgement Number는 이 TCP segment를 받은 호스트가 응답으로 전송해야 할 SEQ Number를 담고 있으며, ACK Flag가 1인 경우에만 유효합니다. SEQ Number에 따른 ACK Number는 아래와 같습니다.
ACK Number = SEQ Number + Data Byte + 1
하지만, ACK를 한번도 받지 않은 경우(Three-Way Handshake를 수행하는 중)에는 SEQ Number를 결정하기 위해 필요한 ACK Number가 없습니다. 이런 경우에는 랜덤 하게 생성된 ISN(Initial Sequence Number)가 SEQ Number로 사용됩니다.
TCP는 Finite-State Machine의 개념을 일부 차용하고 있습니다. 즉, 예상가능한 몇 가지 상태 값을 가지며 특정 입력이 주어질 때마다 상태를 천이(transition)하며 작동하는 방식이죠. 여기서 특정한 입력값은 위의 그림에서 볼 수 있는 8개의 Flag를 통해 입력됩니다. 그중 TCP의 연결과 연결 종료에 사용되는 플래그는 ACK, SYN, FIN입니다. 각각이 의미하는 바는 아래와 같습니다.
- ACK: 상대방 호스트가 보낸 데이터를 받아들였음을 의미합니다.
- SYN: 두 호스트를 연결할 때 SEQ Number를 동기화(synchronize)하기위해 사용됩니다.
- FIN: 상대방 호스트에게 모든 데이터를 전송했음을 알립니다.
Three-Way Handshake
TCP에서는 Three-Way Handshake를 통해 두 TCP소켓이 서로 데이터를 주고받을 준비가 되었는지 확인하는 과정으로 아래와 같은 과정을 거치게 됩니다.
- Client가 SYN segment를 SEQ Number [SEQ = ISN(C)]와 함께 연결하고자 하는 Server TCP 소켓으로 전송합니다. 이 단계에서 TCP Option을 설정할 수 있습니다.
- Server는 SYN+ACK segment를 SEQ & ACK Number[SEQ = ISN(S), ACK = ISN(C) + 1]와 함께 Client로 전송하여 Client가 보낸 SYN요청을 확인했음을 알리고, Client에게 SYN를 요청합니다.
- Client는 ACK segment를 SEQ & ACK Number[SEQ = ISN(C), ACK = ISN(S) + 1]와 함께 Server로 전송하여 Server의 SYN요청을 확인합니다.
위의 과정을 통해 두 호스트는 SEQ와 ACK를 동기화하고, 비로소 데이터를 주고받을 준비를 마치게 됩니다. SYN segment를 먼저 전송하면 active open을 수행했다고 하며, SYN segment를 받고 SYN + ACK segment를 전송하면 passive open을 수행했다고 합니다.
Four-Way Handshake
Four-Way Handshake는 안전하게 두 TCP소켓간의 연결을 종료하는 방법입니다. 두 소켓은 총 네 번의 segment전송을 통해 연결을 종료하게 됩니다.
- active close를 수행할 소켓은 FIN + ACK segment를 전송합니다. ACK는 이전에 상대방 소켓이 전송한 데이터에 대한 승인(acknowledge)을 의미합니다.
- FIN + ACK segment를 수신한 소켓은 해당 segment를 수신했다는 의미로 ACK segment를 상대방 소켓으로 전송합니다. 그리고 해당 호스트의 어플리케이션은 통신을 마무리하는데 필요한 프로세스를 수행합니다. 모든 프로세스가 수행된 다음, 이전에 보낸 segment와 동일한 SEQ & ACK Number를 갖는 FIN + ACK segment를 상대방 소켓으로 전송합니다.
- active close를 수행한 소켓은 FIN + ACK segment를 수신했다는 의미로 ACK segment를 상대방 소켓으로 전송합니다.
소켓의 연결 종료를 수행하는 주체는 어느쪽이 되어도 작동하는 데에는 지장이 없지만, client가 server에 종료 요청을 보내는 것이 일반적입니다. active close를 수행한 소켓은 CLOSE_WAIT라는 시간 동안 동일한 PORT를 사용할 수 없게 되기 때문입니다.
마치며
여기까지 TCP의 기본적인 연결과 연결종료 과정에 대해서 알아보았습니다. TCP 소켓에 대한 더 자세한 내용은 다른 포스팅을 통해 다루도록 하겠습니다.
참고문헌
W. Richard Stevens. 2011. TCP/IP Illustrated, Volume 1. n.p.: Addison Wesley.
윤성우. 2012. 열혈 TCP/IP 소켓프로그래밍. n.p.: 오렌지미디어.
'Fundamentals > SOCKET' 카테고리의 다른 글
[SOCKET] sockaddr 구조체 - sockaddr (0) | 2020.03.06 |
---|