Skip to main content
SYN → SYN-ACK → ACK 는 머리로는 알겠죠? 근데 캡처 화면에서 그 세 줄을 바로 집어내는 건 또 다른 감각이에요.
TCP 3-way handshake는 왜 세 번이나 주고받을까요?에서는 왜 세 번이나 주고받는지를 큰 그림으로 먼저 봤고, tcpdump 한 줄은 어떻게 읽어야 할까요?에서는 한 줄을 어디부터 읽어야 하는지를 먼저 잡았어요. 근데 막상 캡처 화면을 열면 이런 생각이 들죠.
“좋아요, handshake 자체는 알아요. 근데 이 수많은 줄 중에서 어느 세 줄이 그 handshake고, 어디서부터 읽어야 하죠?”
근데 이 글이 진짜 필요한 순간은 캡처를 열고도 handshake를 못 집어낼 때예요.
  • 지금 이 세 줄이 정상 연결 시작인지
  • 아니면 SYN 만 반복되는 재전송 장면인지
  • 아니면 SYN-ACK 까지는 오는데 마지막 ACK가 안 보여서 어디선가 끊기는지
그 판단이 안 서면 캡처를 들여다봐도 여전히 답답하거든요. 오늘은 tcpdump 화면에서 SYN, SYN-ACK, ACK가 실제로 어떻게 찍히는지, 그리고 어디서 끊기면 무엇을 의심해야 하는지까지 같이 볼게요.
여기서는 핸드셰이크 장면을 캡처 위에서 읽는 감각에 집중해요. tcpdump 명령 옵션 전체를 다시 설명하거나, TCP 헤더의 모든 칸을 다시 해부하지는 않을 거예요. 한 줄 읽기 감각은 tcpdump 한 줄은 어떻게 읽어야 할까요?에서, 헤더 칸 자체는 TCP 헤더는 왜 이렇게 칸이 많을까요?에서 이미 봤으니까요. 여기서는 그걸 실제 장면으로 다시 묶어볼게요.

그래서 이 장면은 대체 뭘 보고 있는 걸까요?

이 글에서 보는 건 새로운 프로토콜이 아니에요. 이미 알고 있는 TCP handshake를 캡처 로그 위에서 다시 읽는 장면이에요. 즉 핵심은 이거예요.
  • SYN 이 먼저 보이면 누가 먼저 문을 두드렸는지
  • SYN-ACK 이 보이면 상대가 그 시작 번호를 어떻게 받았는지
  • 마지막 ACK 이 보이면 이제 데이터가 올라갈 준비가 됐는지
를 실제 줄 위에서 읽는 거예요.

먼저 장면부터 볼까요?

실제 캡처에서는 대개 이런 줄을 만나게 돼요.
처음 보면 그냥 긴 문장 세 줄처럼 보이죠. 근데 이건 사실 기본편 handshake 그림캡처 자막으로 바뀐 모습이에요. 이 그림이 중요한 이유는, 캡처에서 handshake를 읽을 때 플래그만 보는 게 아니라 방향과 숫자와 옵션을 같이 본다는 감각을 잡게 해주기 때문이에요.

이 장면에서 먼저 읽어야 할 신호 네 가지

장면 해석형 글에서는 “뭘 먼저 봐야 하지?” 가 제일 중요하잖아요. 이 handshake 장면에서는 우선 이 네 가지부터 보면 돼요.
  1. 누가 먼저 시작했는지Flags [S] 를 누가 먼저 보냈는지
  2. ack 가 왜 1 늘어나는지SYN 이 sequence 공간을 1칸 쓰기 때문
  3. 옵션이 무엇을 같이 협상하는지mss, wscale, sackOK, TS
  4. 세 줄 사이 간격이 자연스러운지 — 재전송인지, 응답 지연인지
이 네 가지를 먼저 보면, 긴 줄도 그냥 “연결이 열렸네” 수준이 아니라 어디까지 정상이고 어디서부터 이상한지 읽히기 시작해요.

한 줄씩 뜯어보면 이렇게 읽어요

같은 세 줄을 표로 펼치면 더 또렷해져요. 여기서 숫자는 일부러 상대 번호(relative sequence number) 느낌으로 단순화해서 썼어요. 실제 환경에서는 절대 sequence 번호가 훨씬 크게 보일 수도 있지만, 초반에는 SYN 뒤엔 ack 가 1 늘어난다는 흐름만 읽혀도 충분해요. 이 감각은 RFC 9293 3.4절과 3.5절에서 설명하는 핵심이기도 해요.

ack = 1 은 왜 이렇게 자주 보일까요?

이건 초심자가 handshake 캡처에서 가장 자주 멈추는 지점이에요. 기본편에서도 봤지만, 다시 한 번 연결해볼게요.
  • 클라이언트가 SYN 을 보냄
  • SYN 자체가 sequence 공간을 1칸 차지함
  • 그래서 서버는 ack 1 로 답함
ACK 는 단순히 “받았어요” 가 아니라, “나는 다음엔 그다음 번호를 기대해요” 에 더 가까워요. 이 해석이 바로 캡처 읽기의 중심이에요. 여기서는 범위를 한 번만 나눠둘게요.
여기서는 seq, ack캡처 위 해석에 집중할게요. 그 숫자 칸이 TCP 헤더 몇 번째 줄에 있는지는 TCP 헤더는 왜 이렇게 칸이 많을까요?에서 다시 펼쳐볼 수 있어요.

옵션은 왜 첫 두 줄에 몰려 있을까요?

핸드셰이크 줄을 보면 mss 1460, sackOK, TS, wscale 7 같은 옵션이 유난히 눈에 띄죠. 이건 단순 장식이 아니에요. 앞으로 데이터를 어떤 규칙으로 주고받을지 초반에 같이 맞추는 과정이거든요.
  • mss 1460 — 한 세그먼트에 어느 정도까지 실을지
  • wscale 7 — 윈도우 값을 나중에 얼마나 크게 해석할지
  • sackOK — 중간에 빠진 조각을 더 똑똑하게 복구할 수 있는지
  • TS — 타임스탬프 옵션을 쓸지
이 옵션들은 RFC 7323 쪽 감각과 이어져요. 특히 Window Scale핸드셰이크에서만 합의되기 때문에, 이 세 줄을 놓치면 나중에 캡처에서 보이는 윈도우 값을 잘못 읽기 쉬워요. 다만 여기서도 한 가지는 꼭 같이 기억하면 좋아요.
어떤 옵션을 실제로 붙이는지는 운영체제와 구현마다 조금씩 달라질 수 있어요. 그러니까 옵션 목록이 완전히 같지 않다고 해서 곧장 이상하다고 읽지는 않아요.
그리고 wscale 값은 양쪽이 똑같아야 하는 공용 숫자라고 생각하면 안 돼요. 클라이언트와 서버가 각자 자기 방향 Window를 어떻게 키워 읽어달라는지 따로 알릴 수도 있어요.

어디서 끊기면 무엇을 의심할까요?

핸드셰이크 캡처가 진짜 빛나는 순간은, 연결이 안 열릴 때 어디서 멈췄는지 보여줄 때예요.

1. SYN 만 반복해서 보이고 SYN-ACK 가 안 와요

이 장면은 보통 상대 응답이 안 보인다는 뜻이에요.
  • 서버가 진짜 응답을 못 했을 수도 있고
  • 중간 방화벽이나 네트워크가 막았을 수도 있고
  • 캡처 위치상 돌아오는 패킷을 못 보고 있을 수도 있어요
즉 이걸 보고 바로 “서버가 죽었네” 라고 단정하면 위험해요. 응답이 없다는 사실왜 응답이 안 보이는지는 다른 이야기거든요.

2. SYN-ACK 까지는 보이는데 마지막 ACK 가 안 보여요

이건 서버는 답했는데, 클라이언트 쪽 마지막 확인이 안 갔거나 안 보인다는 뜻으로 읽기 쉬워요.
  • 클라이언트가 응답을 못 받았을 수도 있고
  • 중간 경로에서 마지막 ACK가 사라졌을 수도 있고
  • 내가 보는 캡처 위치가 한쪽 방향만 담고 있을 수도 있어요

3. 세 줄은 끝났는데 바로 RST 가 보여요

핸드셰이크는 열렸지만, 그다음 애플리케이션이나 중간 장비가 즉시 연결을 접어버리는 장면일 수 있어요. 즉 “연결 열기 실패”“열리긴 했지만 곧장 끊김” 은 완전히 다른 문제예요. 이 차이를 읽으려면 TCP 플래그는 어떻게 읽어야 할까요?에서 봤던 RST 감각이 같이 필요해져요.

근데 왜 handshake를 캡처 위에서 이렇게까지 읽어야 할까요?

1. 누가 먼저 시작했는지 바로 보여줘요

기본편에서는 클라이언트가 먼저 SYN 을 보낸다고 배웠죠. 캡처에서는 그게 실제 어느 IP와 어느 포트였는지까지 바로 보여줘요. 즉 이야기의 주어가 훨씬 선명해져요.

2. 연결이 안 되는 문제를 좁히기 쉬워져요

SYN 만 가는지, SYN-ACK 까지는 오는지, 마지막 ACK 까지 끝나는지에 따라 막힌 위치 후보가 꽤 달라져요.

3. 뒤에서 보는 재전송, 윈도우, 종료 장면의 출발점이 돼요

재전송, TIME-WAIT, RST, 윈도우 크기 해석도 결국은 이 연결이 처음 어떻게 열렸는지 위에 서 있어요. 그래서 핸드셰이크를 캡처에서 읽는 감각은 뒤의 모든 TCP 장면 해석의 출발점이 돼요.

잘못 읽기 쉬운 함정 다섯 가지

하나, SYN 만 보이면 무조건 서버 장애라고 단정하기.
아니에요. 서버, 방화벽, 라우팅, NAT, 캡처 위치 문제까지 다 가능해요.
둘, ack = 1 을 “패킷 한 개 받았어요” 로 읽기.
더 정확히는 sequence 공간에서 다음으로 기대하는 번호예요.
셋, 옵션이 많이 붙으면 이상한 트래픽이라고 생각하기.
오히려 MSS, Window Scale, Timestamp 같은 건 아주 흔한 handshake 옵션이에요.
넷, length 0 이면 아무 일도 없다고 생각하기.
핸드셰이크의 핵심 신호는 오히려 length 0 인 경우가 많아요.
다섯, 캡처에 안 보이면 실제로도 안 일어났다고 믿기.
캡처는 어디서 잡았는지에 따라 빠진 방향이나 빠진 패킷이 있을 수 있어요. 그래서 보이는 장면실제 전체 장면을 늘 같은 것으로 놓으면 안 돼요.

자, 정리해볼까요?

  • tcpdump 위의 handshake는 결국 Flags [S]Flags [S.]Flags [.] 세 줄로 읽히는 경우가 많아요.
  • 이 장면에서는 누가 먼저 시작했는지, ack 가 왜 1 늘어나는지, 어떤 옵션을 같이 협상하는지, 세 줄 사이 간격이 자연스러운지를 먼저 보면 좋아요.
  • SYN 만 반복되는지, SYN-ACK 까지만 보이는지, 세 줄 뒤 바로 RST 가 붙는지에 따라 문제 해석이 달라져요.
  • length 0 은 “빈 패킷”이 아니라, 제어 신호만 오가는 중요한 장면일 수 있어요.
  • 캡처 해석은 플래그만 보는 일이 아니라, 방향 · 숫자 · 옵션 · 위치를 같이 읽는 일이에요.
결국 handshake를 캡처에서 읽는다는 건, 기본편에서 배운 인사를 현장 로그 위에서 다시 알아보는 감각에 가까워요. 그 세 줄이 읽히기 시작하면, 이후의 재전송이나 종료 장면도 훨씬 덜 낯설어져요.

이어서 보면 좋은 글

이 감각이 익숙해지면, 그다음엔 handshake 뒤에 이어지는 재전송, 윈도우, 종료 장면도 훨씬 덜 낯설게 보이기 시작할 거예요.