TCP가 보장하는 것은 메시지가 아니라 바이트의 순서다
TCP는 두 끝점 사이에 신뢰할 수 있고 순서가 있는 바이트 스트림을 제공하는 전송 프로토콜이다. IP는 패킷 손실과 중복, 순서 변경을 허용할 수 있지만 TCP는 시퀀스 번호, 확인 응답, 재전송과 버퍼 관리를 이용해 응용이 바이트를 순서대로 읽게 한다. 이것은 통신 상대의 프로그램이 업무 처리를 성공했다는 보장과는 다르다.
TCP는 바이트의 순서를 보장하며 응용 메시지의 경계는 별도로 정의해야 한다.
바이트마다 위치를 부여한다
보낸 바이트의 위치를 시퀀스 번호로 추적하면 수신자는 빠진 부분과 중복된 부분을 구분할 수 있다. 확인 응답은 일반적으로 다음에 기대하는 바이트 위치를 알리는 방식으로 연속해서 받은 구간을 표현한다. 송신자는 아직 확인되지 않은 데이터를 보관하고 손실을 판단하면 다시 보낸다. 선택적 확인 같은 확장도 손실 복구를 돕는다.
연결 설정에서는 양쪽이 초기 시퀀스 번호와 통신 상태를 맞춘다. 대표적인 과정이 SYN, SYN-ACK, ACK의 세 번 교환이다. 연결이 설정된 뒤 양방향 전송이 가능하며, 한쪽의 송신 종료와 연결 전체의 종료는 구분될 수 있다. 연결을 만들었다고 상대가 이후에도 계속 살아 있는 것을 영구히 증명하는 것은 아니다.
send 두 번은 recv 두 번을 뜻하지 않는다
응용이 hello와 world를 두 번의 send로 보냈어도 수신 쪽은 helloworld를 한 번에 읽거나 더 작은 조각으로 나누어 읽을 수 있다. TCP는 전송 호출의 경계를 응용 메시지의 경계로 유지하지 않는다. 길이 필드, 구분자, 고정 크기 같은 응용 프로토콜 규칙으로 메시지를 재구성해야 한다.
앞부분의 바이트가 유실되면 뒤 바이트가 이미 도착했어도 응용에 순서대로 넘기기 위해 기다릴 수 있다. 이런 지연은 TCP의 순서 보장과 연결되어 있다. 또 신뢰성을 위한 재전송에는 시간과 추가 트래픽이 들며, 수신 측이나 네트워크가 감당할 수 있는 전송량도 제한한다.
TCP 체크섬과 재전송이 암호학적 기밀성을 제공하지는 않는다. 보안 통신에는 TLS 같은 추가 계층이 필요하다. ACK를 받은 사실 또한 데이터가 상대의 커널에 도착했다는 전송 의미와, 데이터베이스에 저장되었다는 업무 의미를 같게 만들지 않는다.
프로그램에서는 부분적인 쓰기와 읽기, 연결 끊김, 타임아웃을 처리해야 한다. 특히 한 번 recv했다고 메시지 전체라고 믿는 코드는 작은 테스트에서는 작동해도 실제 네트워크에서 실패할 수 있다. TCP의 정확한 약속을 바이트 스트림으로 이해하면 메시지 설계와 장애 처리를 함께 올바르게 만들 수 있다.
타임아웃 뒤에 같은 요청을 다시 보내는 경우에는 전송 계층과 업무 계층의 경계를 특히 주의해야 한다. 연결이 끊기기 직전에 서버가 요청을 처리했지만 답만 유실되었을 수 있다. 새 TCP 연결을 만든다고 이전 업무 처리 사실이 사라지지는 않는다. 예를 들어 결제나 주문 생성은 요청 식별자와 중복 처리 정책을 함께 설계해야 한다. TCP 내부의 중복 바이트 제거는 한 연결의 스트림을 복원하는 기능이고, 재연결한 응용의 동일 업무를 판별하는 기능은 아니다. 반대로 서버가 일부 바이트만 받은 상태에서 종료했을 수도 있다. 응용은 성공 응답의 의미, 실패 후 조회 방법, 재시도의 안전성을 명시해야 한다.