← Posts

Network · TCP · Handshake

안 끊기고 순서대로 오게 - TCP

인터넷은 패킷을 잃기도 뒤섞기도 한다. 그런데 웹페이지는 한 글자도 안 틀리고 순서대로 도착한다. 그 신뢰성을 맡는 TCP - 먼저 악수로 연결을 맺고, 조각마다 받았다는 확인을 주고받으며, 잃은 건 다시 보낸다.

목차
  1. 안 끊기고 순서대로 와야 한다
  2. TCP는 신뢰성을 맡는다
  3. 먼저 악수부터: 3-way handshake
  4. 왜 굳이 악수를 하나
  5. 조각으로 쪼개 보낸다
  6. 받았다고 알려준다: 확인응답
  7. 순서를 맞춰 조립한다
  8. 그 위에 TLS와 HTTP가 얹힌다
  9. 실무에서: 악수 비용과 연결 재사용
  10. 정리

IP는 패킷을 목적지로 보내지만, 도착을 보장하진 않는다. 잃어버리기도, 순서가 뒤섞이기도 한다. 그런데 웹페이지는 멀쩡히 온다. 그 신뢰성을 책임지는 게 TCP다. 연결부터 맺어야 한다던 그 연결이 이것이다.

안 끊기고 순서대로 와야 한다

IP는 패킷을 “일단 보내는” 것까지만 한다. 도중에 사라질 수도, 늦게 도착해 순서가 뒤바뀔 수도 있다. IP만 믿으면 웹페이지가 군데군데 빠지거나 뒤죽박죽 와야 한다.

하지만 실제론 한 글자도 안 틀리고 순서대로 온다. 그 사이에서 “잃은 건 다시 받고, 뒤섞인 건 제 순서로 맞추는” 일을 TCP가 한다. IP 위에 얹혀 신뢰성을 더하는 층이다.

TCP는 신뢰성을 맡는다

TCP가 맡는 신뢰성은 세 가지다.

  • 빠짐없이 - 잃어버린 조각을 다시 보내 하나도 안 빠지게.
  • 순서대로 - 뒤섞여 도착해도 원래 순서로 다시 맞춰서.
  • 연결 위에서 - 주고받기 전에 양쪽이 “이제 시작하자”고 맺은 연결 안에서.

이걸 해내려고 TCP는 먼저 악수를 하고, 데이터를 조각으로 나눠 번호를 붙이고, 조각마다 받았다는 확인을 주고받는다. 하나씩 보자.

먼저 악수부터: 3-way handshake

TCP는 데이터를 보내기 전에 연결을 맺는다. 양쪽이 세 번 인사를 주고받는 이 과정을 3-way handshake라 한다.

diagramdiagram

클라이언트가 “연결하자”(SYN)고 하면, 서버가 “그래, 나도 준비됐다”(SYN-ACK)고 답하고, 클라이언트가 “좋다, 시작하자”(ACK)고 마무리한다. 이 세 번이 오가야 비로소 데이터를 보낼 수 있다.

왜 굳이 악수를 하나

한 번에 데이터부터 보내면 될 것 같은데 왜 세 번이나 인사할까. 양쪽이 서로 주고받을 준비가 됐는지 확인하기 위해서다.

  • 서버가 살아 있고 이 포트에서 받을 준비가 됐는지,
  • 양쪽이 앞으로 쓸 시작 번호를 맞췄는지(뒤의 순서 맞추기에 쓴다),
  • 서로의 신호가 오가는지(양방향이 다 되는지)

를 데이터를 보내기 전에 확정한다. 그래서 connection 글이 “요청을 보내기 전에 해야 할 일이 있다”고 한 것이다 - 그 “할 일”이 이 악수다. 악수에도 왕복 시간이 드니, 이 비용을 아끼려고 연결을 재사용한다.

조각으로 쪼개 보낸다

데이터는 통째로 안 간다. TCP는 큰 데이터를 조각(세그먼트) 으로 쪼개고, 각 조각에 순서 번호를 붙인다.

plaintext
보낼 데이터:  [ 안녕하세요 반갑습니다 ... ]
쪼개면:       [1:안녕][2:하세요][3:반갑][4:습니다] ...

번호가 붙어 있으니, 조각들이 여러 홉을 거치며 뒤섞여 도착해도 받는 쪽이 번호대로 다시 맞출 수 있다. 이 번호가 신뢰성의 열쇠다.

받았다고 알려준다: 확인응답

TCP는 조각을 받으면 “몇 번까지 잘 받았다”고 알려준다(ACK). 보낸 쪽은 이 확인을 기다린다.

plaintext
보냄:  3번 조각 →
       ← ACK "3번까지 받음"   (잘 도착)

보냄:  4번 조각 →   (도중에 사라짐)
       ...확인이 안 옴...
       4번 조각 다시 보냄 →    (재전송)
       ← ACK "4번까지 받음"

정해진 시간 안에 확인이 안 오면, 보낸 쪽은 “잃어버렸구나” 하고 다시 보낸다. 이 확인·재전송 덕에 조각이 도중에 사라져도 결국 빠짐없이 전해진다. IP는 잃어버려도 모르지만, TCP는 알아채고 메운다.

순서를 맞춰 조립한다

받는 쪽은 조각들을 번호대로 다시 조립한다. 4번이 5번보다 늦게 와도, 번호를 보고 4번을 앞에 놓는다. 아직 안 온 번호가 있으면 그 자리를 비워두고 기다렸다가, 도착하면 채운다.

그래서 위층(HTTP)이 받는 데이터는 항상 보낸 순서 그대로, 빠짐없이다. 뒤섞이고 잃어버리는 IP의 현실을 TCP가 가려주니, HTTP는 그 아래가 얼마나 지저분한지 모른 채 깨끗한 데이터만 받는다.

그 위에 TLS와 HTTP가 얹힌다

TCP 연결이 맺어지면, 그 위에 다시 TLS와 HTTP가 얹힌다. 계층이 이렇게 쌓인다.

plaintext
HTTP          (무엇을 주고받나)
 └ TLS        (암호화 - https-tls의 몫)
    └ TCP     (안 끊기게, 순서대로 - 이 글)
       └ IP   (어느 기계로)

그래서 HTTPS 접속은 TCP 악수를 하고, 그 위에서 TLS 핸드셰이크를 또 한 뒤, 그제야 HTTP를 주고받는다. 악수가 이중이라 첫 연결이 그만큼 걸린다 - 이 비용을 줄이려는 게 HTTP 버전이 올라온 이유다.

실무에서: 악수 비용과 연결 재사용

  • 첫 연결이 제일 비싸다 - TCP 악수 + TLS 핸드셰이크의 왕복이 첫 요청에 얹힌다. 그래서 연결을 끊지 않고 재사용하는 게 중요하다 - 두 번째 요청부터는 악수를 건너뛴다.
  • 연결도 자원이다 - 맺은 TCP 연결은 양쪽에서 소켓(fd)을 잡는다. 너무 많이 열면 fd가 마른다. 그래서 연결 풀로 아껴 쓴다.
  • 끊김을 감지하는 데 시간이 걸린다 - 상대가 조용히 죽으면, 이쪽은 확인이 안 오는 걸로 한참 뒤에야 안다. 그래서 타임아웃과 헬스체크로 빨리 알아채게 한다.

정리

  • IP는 패킷을 잃고 뒤섞지만, TCP가 그 위에서 빠짐없이·순서대로·연결 위에서 신뢰성을 더한다.
  • 데이터 전에 3-way handshake(SYN·SYN-ACK·ACK)로 연결을 맺는다 - 양쪽이 준비됐는지 확인하는 그 “할 일”이다.
  • 데이터를 번호 붙인 조각으로 쪼개, 확인응답(ACK) 으로 도착을 확인하고 안 온 건 재전송하며, 번호대로 다시 조립한다.
  • TCP 위에 TLS·HTTP가 얹혀, 첫 연결은 악수가 이중이라 비싸다 - 그래서 연결을 재사용한다.

다음 글은 이 모든 안전장치를 일부러 버리고 속도를 택하는 반대편 - UDP로 간다.

관련 글