TCP 택배가 잘려 도착했다 · 반닫힌 연결에서 마지막 답을 돌려준다 · 실습
망가진 택배의 경계를 되살린다
목표
프레이밍·기한·반닫힘을 구현하고 실제 TCP에서 확인합니다.
왜 중요한가
받은 조각을 메시지 하나라고 믿으면 로컬에서는 성공해도 실제 입력에서 깨집니다. 길이와 전체 시간 예산, 소켓 소유권을 코드로 표현해 데이터 유실과 무한 대기를 구분합니다. 표준 라이브러리만 사용하고 인터넷 접속이나 설치는 필요 없습니다.
단계
1. 봉투에는 글자 수가 아니라 바이트 수 — codec.py에 MAX_PAYLOAD=4096과 encode(payload)를 만드세요. bytes 본문 앞에 unsigned 4바이트 big-endian 길이를 붙여 bytes를 반환합니다. 빈 본문은 허용하고 bytes가 아니거나 4096바이트를 넘으면 ValueError입니다.
2. 헤더도 반으로 잘릴 수 있다 — codec.py에 Decoder를 추가하세요. 새 인스턴스마다 수신 상태가 분리되고 feed(chunk: bytes)는 완성된 본문의 list[bytes]를 반환합니다. 한 프레임을 어느 바이트에서 잘라 두 번 공급해도 복원하고, 미완성 데이터는 다음 호출까지 보관합니다.
3. 택배 셋이 한 봉지로 왔다 — Decoder.feed를 개선해 한 chunk에 여러 프레임이 있으면 순서대로 모두 반환하세요. 다음 프레임의 일부가 남으면 보관합니다. 빈 본문도 메시지 하나이며, 빈 chunk는 EOF가 아닙니다.
4. 도착 완료와 배송 중 파손 — Decoder.finish()를 만드세요. 미완성 헤더나 본문이 있으면 EOFError, 잔여가 없으면 None을 반환합니다. 정상적으로 해석한 길이 0 본문을 중간 종료로 오해하지 마세요.
5. 4 GiB 택배 예고장을 거절한다 — Decoder는 4096보다 큰 길이 헤더를 받는 즉시 ValueError를 내야 합니다. 실제 본문이 도착할 때까지 기다리거나 그 길이의 버퍼를 먼저 할당하지 마세요. 4096바이트 본문은 여전히 허용합니다. 오류 후 해당 연결은 폐기합니다.
6. 한 글자씩 보내면 영원히 기다릴까 — transport.py에 recv_frame(sock, timeout, clock=None)을 구현하세요. 한 프레임의 헤더와 본문 전체가 같은 시간 예산을 공유합니다. clock은 인자 없는 초 단위 시계 함수이며 기본은 time.monotonic입니다. sock의 gettimeout/settimeout/recv만 사용합니다. 정상 프레임은 bytes, 새 헤더를 한 바이트도 받기 전 EOF는 None, 중간 EOF는 EOFError, 초과 길이는 ValueError, 기한 초과는 TimeoutError입니다. 양의 유한 timeout만 허용하고 성공·실패 모두 이전 소켓 timeout을 복원하세요.
7. 보냈다는 말의 절반만 사실 — transport.py에 send_frame(sock, payload)를 추가하세요. encode한 전체 프레임을 보내고, 전송 오류를 숨기지 않습니다. send가 일부 바이트만 처리하는 경우에도 프레임을 빠뜨리지 않아야 합니다. 호출자가 소켓의 송신 timeout을 정합니다.
8. 실제 연결로 반송장을 받는다 — server.py에 handle_connection(sock, timeout)을 만드세요. 받은 소켓의 소유권을 인수하고 프레임마다 같은 bytes를 에코합니다. recv_frame의 정상 EOF(None)에서 종료하되 b"" 본문은 에코합니다. 모든 종료 경로에서 소켓을 닫고 프로토콜 오류는 호출자에게 전달하세요. 검사기가 127.0.0.1의 임시 포트에서 실제 TCP 연결을 만들며, 클라이언트가 송신만 반닫은 뒤에도 남은 응답을 받아야 합니다.
참고
모든 파일은 /root/tcp-parcel 아래에 둡니다. 예시 파일에는 정답이 아닌 함수 틀이 있습니다. 이전 단계 함수도 계속 유지하세요. 채점은 제출 코드를 실행하며 12초가 넘으면 중단합니다. send_frame의 송신 timeout은 호출자가 정합니다. 실습 세션 종료 후 파일은 유지되지 않으므로 별도로 보관하세요.
단계 8개
- 봉투에는 글자 수가 아니라 바이트 수
- 헤더도 반으로 잘릴 수 있다
- 택배 셋이 한 봉지로 왔다
- 도착 완료와 배송 중 파손
- 4 GiB 택배 예고장을 거절한다
- 한 글자씩 보내면 영원히 기다릴까
- 보냈다는 말의 절반만 사실
- 실제 연결로 반송장을 받는다