네트워크 미니랩 3/5 · TCP는 왜 세 번 인사할까?
네트워크 미니랩 세 번째. TCP 3-way handshake를 네 장면과 쉬운 대화로 이해합니다.

목차
전화를 걸면 바로 용건부터 말하지 않습니다.
"여보세요?" — "네, 말씀하세요." — "아 네."
TCP도 똑같습니다. 데이터를 보내기 전에 세 번의 인사로 서로 준비됐는지 확인합니다. 이 데모는 그 과정 하나만 보여줍니다.
세 번의 인사가 하는 말
- 시작 요청(SYN) — "대화 시작할까요? 제 번호는 100부터예요."
- 서버 응답(SYN-ACK) — "좋아요, 잘 받았어요(ACK 101). 제 번호는 300부터예요."
- 마지막 확인(ACK) — "저도 확인했어요(SEQ 101, ACK 301). 시작할게요!"
ACK 값은 다음에 받고 싶은 번호입니다. 이 예제에서는 SYN이 번호 하나를 차지하므로 100 다음은 101, 300 다음은 301이 됩니다. 일반 데이터에서는 받은 바이트 길이만큼 번호가 앞으로 갑니다.
왜 세 번일까요?
두 번째 인사까지는 서버가 보낸 시작 번호가 클라이언트에 도착했는지 서버가 모릅니다. 세 번째 ACK이 와야 양쪽의 시작 번호가 모두 전달되고 확인됐음을 알 수 있습니다. 이 과정은 오래전에 떠돌던 중복 연결 요청을 새 연결로 착각할 가능성도 줄입니다.
이때 교환한 시작 번호(SEQ)는 이후 데이터가 잘리고 뒤섞여 도착해도 순서를 맞추는 기준이 됩니다. 네트워크 7계층 랩에서 예시로만 보여줬던 "순서 번호"가 여기서 정해지는 것입니다.
데모에서 해볼 일
- 첫 인사 보내기를 누르고 세 문장만 따라갑니다.
- 양쪽 카드가 연결 완료로 바뀌는 순간을 확인합니다.
- 숫자가 궁금할 때만 말풍선의 SEQ·ACK 번호 보기를 펼칩니다.
인사가 실패하면 어떤 모습으로 보일까
세 번의 인사는 잘될 때보다 안 될 때 더 자주 마주칩니다. 접속이 안 되는 증상은 크게 둘로 갈리는데, 갈리는 지점이 바로 첫 번째 SYN입니다.
- 바로 거절당하는 경우 — 상대가 그 포트에서 아무것도 듣고 있지 않으면 연결을
끊자는 신호(RST)를 곧바로 돌려보냅니다.
Connection refused가 거의 즉시 뜹니다. 서버까지는 도달했는데 프로세스가 죽었거나 다른 포트를 쓰고 있을 때의 모습입니다. - 한참 멈춰 있는 경우 — 중간의 방화벽이 SYN을 조용히 버리면 답 자체가 오지
않습니다. 보낸 쪽은 첫 인사가 유실됐다고 보고 SYN을 몇 번 더 보내면서 간격을
두 배씩 늘립니다. 리눅스 기본값인
tcp_syn_retries = 6이면 포기할 때까지 약 127초가 걸립니다.
즉 즉시 거절이면 서버 안쪽, 오래 멈추면 중간 경로나 방화벽을 먼저 의심할 수 있습니다. 증상을 이렇게 한 번 나누는 것만으로 확인할 범위가 크게 줄어듭니다.
내 컴퓨터에서 직접 확인하기
데모는 그림이지만 같은 일이 지금 내 컴퓨터에서도 일어나고 있습니다.
# 세 번의 인사만 골라 보기 (관리자 권한 필요)
sudo tcpdump -n 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0 and host example.com'
# 지금 맺어진 연결과 상태 보기
ss -tan
ss 출력의 SYN-SENT는 첫 인사를 보내고 답을 기다리는 중이라는 뜻이고,
ESTAB은 세 번의 인사가 모두 끝난 상태입니다. 위의 "한참 멈춰 있는 경우"에
ss를 보면 SYN-SENT가 오래 남아 있습니다.
이 인사를 아낄 수 있을까
핸드셰이크는 데이터를 한 바이트도 보내기 전에 왕복 한 번을 씁니다. 왕복 시간이 100ms인 서버라면 연결을 새로 만들 때마다 0.1초를 먼저 쓰는 셈입니다.
그래서 브라우저와 HTTP 클라이언트는 한 번 만든 연결을 재사용합니다(keep-alive). 이미지 50장을 받으려고 연결을 50번 새로 만들지 않는 이유입니다. 연결을 재사용하면 인사는 처음 한 번만 하고 그 위로 요청을 계속 흘려보냅니다.
연결이 만들어진 다음 조각이 사라지면 어떻게 될까요? 패킷 손실/재전송 랩에서 이어집니다.
이 인사를 내 코드에서는 어떤 함수로 부를까요? connect() 한 줄입니다.
그 앞뒤로 서버가 무엇을 하는지는
소켓 통신 랩에서 볼 수 있습니다.
요약 세 가지
- TCP는 SYN → SYN-ACK → ACK 세 번의 인사로 연결을 만듭니다.
- 세 번째 ACK까지 와야 양쪽의 시작 번호가 모두 확인됩니다.
- 이때 교환한 번호가 이후 데이터의 순서를 지켜줍니다.
참고
데모의 시작 번호 100·300은 읽기 쉽게 고른 예시값입니다(실제로는 공격자가
예측하기 어렵게 선택합니다).
연결 종료(FIN), 재전송, TLS는 다루지 않습니다. 실제 핸드셰이크는 Wireshark
에서 tcp.flags.syn == 1 필터로 볼 수 있습니다.
자료: RFC 9293 (TCP) — Establishing a Connection,
Linux tcp(7) — tcp_syn_retries

