iBetter Books
수정

3-way handshake — 왜 세 번인가

인터넷을 통해 데이터를 주고받기 전에 TCP는 반드시 연결부터 맺습니다. 그 과정에서 패킷이 세 번 오갑니다. SYN, SYN/ACK, ACK. 이 세 번의 교환을 3-way handshake라 부릅니다. 기술 면접에서 단골로 나오는 질문이 있습니다. "왜 두 번도 아니고 네 번도 아니고 꼭 세 번인가요." 단순히 과정을 암기해서는 이 질문에 제대로 답하기 어렵습니다. 설계 이유부터 이해해야 합니다.

TCP 연결이 해야 할 일

두 컴퓨터가 신뢰성 있는 통신을 하려면 연결 시작 전에 반드시 합의해야 할 것들이 있습니다.

첫째, 서로 데이터를 보낼 준비가 됐는지 확인해야 합니다. 한쪽만 준비됐다고 되는 게 아닙니다. TCP는 양방향 통신이므로 클라이언트에서 서버로 가는 방향과, 서버에서 클라이언트로 가는 방향 양쪽 모두 열려야 합니다.

둘째, 각자의 초기 순서 번호(ISN, Initial Sequence Number)를 상대방에게 알려야 합니다. TCP는 데이터를 순서 번호로 관리합니다. 데이터를 보낼 때 "이 데이터는 몇 번입니다"라고 번호를 붙이고, 받는 쪽은 "몇 번까지 받았습니다"라고 확인합니다. 그러려면 처음 시작하는 번호를 서로가 알아야 합니다.

두 번으로는 왜 안 되나

클라이언트가 "연결하고 싶다, 내 초기 순서 번호는 100이야"라고 보내고, 서버가 "알았다, 내 초기 순서 번호는 300이야"라고 응답한다고 해봅니다. 이것이 2-way입니다.

문제는 서버 입장에서 자신의 ISN 300을 클라이언트가 제대로 받았는지 알 수 없다는 점입니다. 클라이언트는 서버의 ISN을 알고 있지만, 서버는 클라이언트가 그 번호를 확인했다는 증거가 없습니다. 서버에서 클라이언트 방향의 통신 경로가 정상인지 검증되지 않은 채 데이터 전송이 시작됩니다.

네 번이라면 어떨까요. 이미 세 번으로 충분한 정보 교환이 완료됩니다. 네 번째는 불필요한 라운드트립(왕복 지연)을 추가할 뿐입니다.

세 번이 딱 맞는 이유

세 번의 과정은 이렇습니다.

첫째, 클라이언트가 SYN 패킷을 보냅니다. "연결하고 싶다. 내 초기 순서 번호는 X야."

둘째, 서버가 SYN/ACK 패킷을 보냅니다. "X 받았다, 알았어(ACK). 나도 연결하고 싶다. 내 초기 순서 번호는 Y야(SYN)."

셋째, 클라이언트가 ACK 패킷을 보냅니다. "Y 받았다, 알았어."

이 세 번이 끝나면 무엇이 확인됐을까요. 클라이언트는 서버의 ISN Y를 알고, 서버는 클라이언트가 자신의 ISN Y를 확인했다는 것도 압니다. 클라이언트 입장에서 서버로 가는 경로(1번 패킷)와 서버에서 클라이언트로 오는 경로(2번 패킷)가 둘 다 살아 있음이 증명됩니다. 서버 입장에서도 마찬가지입니다. 양방향 통신 경로 모두 검증된 상태가 됩니다.

순서 번호는 왜 0이 아닌가

초기 순서 번호를 매번 다른 값으로 시작하는 이유도 설계적입니다. 항상 0부터 시작한다면 직전 연결에서 늦게 도착한 패킷이 새 연결의 패킷으로 오해받을 수 있습니다. 임의의 큰 숫자에서 시작함으로써 이 충돌 가능성을 낮춥니다.

3-way handshake 이후 본격적인 데이터 교환이 시작됩니다. 다음 절에서는 데이터가 오가는 과정에서 순서를 보장하고 잃어버린 패킷을 재전송하는 메커니즘을 살펴봅니다.