[네트워크/Network] TCP 연결 관리와 2, 3, 4 Way Handshaking(핸드쉐이킹)에 대해

kindof

·

2021. 9. 8. 00:22

📋 1. 오버뷰(Overview)

아래 간략한 설명을 보면서 TCP 핸드셰이킹에 대해 감을 잡아보겠습니다.

 

TCP는 애플리케이션 프로세스가 데이터를 다른 프로세스에게 보내기 전에, 두 프로세스가 서로 "핸드셰이크"를 먼저 해야 한다는 것에서부터 연결지향형(connection-oriented)이라는 특징을 갖고 있습니다.

 

한 호스트에서 동작하는 프로세스가 다른 호스트의 프로세스와 연결하고 싶다고 해볼까요? 이 때, 연결을 초기화하는 프로세스를 클라이언트 프로세스, 다른 프로세스를 서버 프로세스라고 하겠습니다.

 

클라이언트 애플리케이션 프로세스는 서버 측의 프로세스와 연결을 설정하기를 원한다고 TCP 클라이언트에게 먼저 말합니다. 그러면 첫번째 TCP 세그먼트를 통해 서버 측 프로세스에게 알림이 가겠죠. "A 클라이언트가 너랑 연결하고 싶대" 이에 대해 서버는 두 번째 특별한 TCP 세그먼트를 통해 "좋아" 라는 응답을 하고, 마지막으로 클라이언트가 세번째 특별한 세그먼트로 응답 "오케이!" 합니다.

 

지금까지 간단하게 설명한 내용이 바로 세 방향 핸드셰이크(3-Way Handshake)에 대한 개념입니다. 그렇다면 이제 구체적인 세 방향 핸드셰이크의 동작 원리에 대해 알아볼텐데요. 그 전에 우선 핸드셰이크라는 개념 자체는 TCP 프로토콜에서 이루어지는 것이다보니, 그 원리를 알기 위해서는 TCP 세그먼트의 구조를 한 번 살펴봐야할 것 같습니다.

 

 

 

📒 2. TCP 세그먼트의 구조

TCP 세그먼트는 헤더 필드와 데이터 필드로 구성되어 있고, TCP 헤더는 상위 계층 어플리케이션으로부터 다중화와 역다중화를 하는 데 사용하는 출발지(source)와 목적지(destination) 포트 번호를 포함합니다.

 

OSI 7계층에 대해 정리한 글에서 어플리케이션 계층, 트랜스포트 계층 등에 대해 다뤘고, TCP는 트랜스포트 계층에서 사용하는 프로토콜이라는 것을 말했었습니다. 혹시 궁금하신 분은 아래 글을 참고하면 좋을 것 같습니다.

 

 

[네트워크/Network] 네트워크의 기본: OSI 계층 구조와 캡슐화

🤔 0. 개요 "OSI 7계층이 무엇인가요?" "컴퓨터 네트워크를 왜 7계층으로 나누나요?" "메시지, 데이터그램, 세그먼트의 차이와 캡슐화는 무엇인가요?" CS를 공부해본 사람이라면 한 번쯤은 OSI 7계층

studyandwrite.tistory.com

 

또한 TCP 세그먼트에는 32비트 순서번호 필드(sequence number field)와 32비트 확인응답번호 필드(acknowledgement number field)가 존재하는데, 이 필드들은 신뢰적인 데이터 전송 서비스 구현에서 TCP 송신자와 수신자에 의해 사용됩니다.

 

그 외에도 헤더 길이 나타내는 필드, 옵션 필드, 플래그 필드 등을 가지고 있는데, 아래 그림에서 플래그(flag) 필드 6비트 안에는 ACK, RST, SYN, FIN 비트가 포함되어 있습니다. 그리고 여기에 있는 SYN 비트가 3-Way Handshake에 쓰이게 되는 녀석이죠.

TCP 세그먼트 구조

 

 

🤝 3. 세 방향 핸드셰이크(3-Way Handshake)

이제 세 방향 핸드셰이크가 왜, 어떻게 일어나는지 조금 더 구체적으로 살펴보겠습니다.

 

[1단계]

먼저 클라이언트 측 TCP는 서버 TCP에게 특별한 TCP 세그먼트를 송신합니다. 이 특별한 세그먼트는 애플리케이션 계층 데이터를 포함하지 않고, 세그먼트의 헤더에 SYN 비트라고 불리는 하나의 플래그 비트를 가집니다.

 

이러한 이유 때문에 이 최초의 세그먼트를 SYN 세그먼트라고 부릅니다. 그리고 클라이언트는 최초의 순서번호(client_isn)을 여기 세그먼트 순서번호 필드에 넣어둡니다. 이 세그먼트는 IP 데이터그램 안에서 캡슐화되고 서버로 송신되죠.

 

[2단계]

TCP SYN 세그먼트를 포함하는 IP 데이터그램이 서버 호스트에 도착했을 때, 서버는 데이터그램으로부터 TCP SYN 세그먼트를 뽑아냅니다. 이를 역다중화(Demultiplexing)이라고 합니다. 그리고 연결에 필요한 TCP 버퍼와 변수들을 할당하고 클라이언트 TCP로 연결 승인 세그먼트를 송신한다. 여기에서 보내는 승인 세그먼트에도 애플리케이션 계층 데이터를 포함하지 않습니다.

 

그러나 세그먼트 헤더 안에 3개의 중요한 정보를 담습니다. 1) SYN 비트를 1로 설정, 2) TCP 세그먼트 헤더의 확인응답 필드는 client_isn+1로 설정, 3) 자신의 최초 순서번호(server_isn)을 선택하고 TCP 세그먼트 헤더의 순서번호 필드에 이 값을 넣는 것.

 

이 연결 승인 세그먼트는 "나는 너의 최초 순서번호(client_isn)을 가지고 연결을 시작하려고 너의 SYN 패킷을 받았어. 나도 연결 승인할테니까 내 최초 순서번호는 server_isn이야!"라고 말한다고 이해하면 될 것 같습니다.

 

[3단계]

클라이언트가 서버가 보낸 SYNACK 세그먼트를 받으면 서버로 또 다른 세그먼트를 송신해야 합니다. 분명히 양방향으로 한 번씩 메시지가 왔다갔다한 것 같은데, 왜 한 번 더 세그먼트를 보낼까요? 이에 대한 궁금증은 아래에서 다루겠습니다.

 

어쨌든, 마지막 세그먼트가 서버의 연결 승인 세그먼트를 확인하는데, 연결이 설정되었기 때문에 SYN 비트는 다시 0으로 설정됩니다.

.

.

.

 

지금까지 설명한 내용을 아래 그림과 함께 마지막으로 정리해보겠습니다.

 

3-Way Handshake

 

1) 클라이언트 측 TCP 프로토콜에서는 연결하자는 뜻으로 SYN(SYNchronize) 패킷과 함께 초기 순서 번호를 서버 측에게 보냅니다.

 

2) 서버는 클라이언트 초기 순서 번호가 X 것을 알게 되고, 클라이언트에게 SYN, ACK 합쳐진 패킷을 보내면서 자신의 초기 순서 번호가 Y임을 알려줍니다.

 

3) 마지막으로 클라이언트 서버로부터 초기 순서 번호를 받았다는 의미로 ACK 보냅니다.

 

과정을 통해 호스트는 신뢰성 있는 통신을 있는 준비를 마치게 됩니다.

 

 

🧐 4. 왜 2-Way Handshake는 안되나? 

위에서 잠깐 '마지막 세번째 응답은 왜 필요한거지?'라는 궁금증에 대해 지적했습니다. 이 마지막 응답은 왜 필요할까요?

위 그림을 예로 들어 보겠습니다. 위 그림은 호스트 A가 호스트 B에게 연결 요청을 한 것이 딜레이가 많이 되어 다시 연결 요청을 하는 상황입니다. 이 경우 호스트 B는 과거의 연결 요청에 대한 순서 번호로 응답을 하게 되고, 호스트 A는 잘못된 순서 번호의 패킷이 왔기 때문에 그 패킷을 버리게 되죠.

 

그런데 만약 두 방향 핸드쉐이크가 끝이라고 하면 어떻게 될까요...? B 입장에서는 A가 내 응답을 제대로 받았는지 확인할 수 없겠죠. 그래서 B혼자 연결되었구나? 하고 오해할 수 있는 것입니다.

 

TCP의 근본은 양방향 연결인데, 이렇게 되버리면 TCP의 근본이 깨져버리게 되고 신뢰성을 보장할 수 없습니다. 따라서 세 방향 핸드쉐이크를 통해 양쪽이 모두 연결되었는가를 보장해줘야만 하는 것입니다.

 

😴 5. 연결 종료와 4-Way Handshake

 

네 방향 핸드셰이크

 

클라이언트와 서버가 연결을 종료할 때도 핸드쉐이크 과정이 필요합니다. 한 쪽이 일방적으로 연결을 끊어버리면 신뢰적인 데이터 전송이 안되겠죠?

 

연결이 종료될 때는 네 단계를 거치게 됩니다.

 

1) 호스트 A 연결 종료를 하자는 FIN 패킷을 호스트 B에게 보내면

2) 호스트 B 응답으로 ACK 패킷을 호스트 A에게 보낸다.

3) 호스트 B 이제 남은 데이터를 모두 전송한 FIN 패킷을 호스트 A에게 보내고,

4) 호스트 A 응답으로 ACK 패킷을 호스트 B에게 보낸다.

 

핵심은 FIN 패킷을 보낸 시점부터 더 이상 데이터 전송이 불가능하다는 것과 클라이언트가 일정 시간 TIME_WAIT을 두는 것입니다.

 

서버에서 FIN을 전송하기 전에 전송한 패킷이 라우팅 지연이나 패킷 유실로 인한 재전송 등으로 FIN보다 늦게 도착할 것을 염려한 것이죠.

 

그래서 클라이언트는 서버로부터 FIN을 수신해도 일정시간동안 세션을 열어놔두어야 합니다.

 

 

6. 끝

이번 포스팅은 짧게 정리하고 끝내려고 했는데 글이 조금 길어진 것 같습니다.

 

그래도 한 번 다시 정리해보니 좋은 시간(?)이었던 것 같습니다.

 

감사합니다.