요약

  • FTP의 초기 재시작 마커는 블록 또는 압축 전송 프레이밍 안에 있었습니다.110 MARK ssss = rrrr응답은 송신자가 관리하는 위치와 수신자가 안정 저장소에 확정한 위치를 짝지어 보냈습니다.
  • 이 짝은 단순한 개수가 아니라 로컬 변환 상태까지 담을 수 있었습니다. RFC 1123의 예제에서는 수신자가 네트워크 CRLF를 로컬 줄바꿈 하나로 변환하며 캐리지 리턴을 이미 소비했다는 사실을 기억해야 했습니다.
  • RFC 3659는 나중에REST STREAM을 바로 이어지는 전송에 적용되는 옥텟 개수로 정의하면서, 소스 또는 부분 수신물이 변경되면 재시작이 안전하지 않다고 경고했습니다. 오프셋은 이어하기 지시일 뿐, 파일 신원이나 무결성 증명이 아니었습니다.

파일을 멈추지 않은 채 도착한 응답

FTP는 처음부터 대화와 화물을 분리했습니다. 명령과 번호가 붙은 응답은 제어 연결을 통해 오가고, 파일 내용은 별도의 데이터 연결로 이동합니다. 이 분리 덕분에 특이한 사건이 가능했습니다. 데이터가 계속 흐르는 동안 수신 측은 제어 채널로110응답을 보내 양쪽 끝이 나중에 복구할 수 있는 지점을 보고할 수 있었습니다.

RFC 1123에서 정정된 형식은 의도적으로 대칭입니다:

110 MARK ssss = rrrr

문자열ssss는 데이터 스트림에 나타났으며 송신자 파일 시스템의 위치를 인코딩했습니다. 문자열rrrr는 수신자 파일 시스템의 해당 위치를 인코딩했습니다. 각 마커는 같은 시스템이 생성하고 나중에 해석했습니다. 등호는 두 문자열이 수치적으로 같다는 뜻이 아니었습니다. 두 위치가 하나의 복구 경계에서 만난다는 뜻이었습니다.

이 응답은 일시정지 지시도 아니었습니다. 재시작 마커를 내보내는 송신자는110응답이 동기적으로 돌아온다고 가정하는 것이 금지되었습니다. 각 체크포인트가 돌아오기를 기다리지 않고 계속 보내야 했습니다. 복구 증거는 실질 작업보다 뒤처질 수 있었습니다.

이것이 현대 인터페이스가 감추는 첫 번째 구분입니다. 진행률 카운터는 관측된 이동량을 말합니다. 재시작 체크포인트는 장애 이후 양쪽이 어느 이전 상태를 재구성할 수 있는지를 말합니다. 단순한 바이트 보존 전송에서는 둘이 일치할 수 있습니다. FTP는 그렇지 않은 경우가 잦은 시스템을 위해 설계되었습니다.

마커에는 프레임 모드가 필요했다

RFC 959는 세 가지 전송 모드를 정의했습니다. 스트림 모드는 비구조적 시퀀스를 보내고 보통 데이터 연결을 닫는 것으로 파일 끝을 알렸습니다. 명세는 그 종결이 본질적으로 신뢰할 수 없다고 말합니다: 연결 닫기만으로는 파일이 정상적으로 끝났는지, 연결이 조기에 끊겼는지 알 수 없습니다. 블록 모드와 압축 모드는 명시적 종료 조건을 포함한 자체 FTP 프레이밍을 실었습니다.

블록 모드에서는 3옥텟 헤더가 각 블록 앞에 붙습니다. 최상위 옥텟은 디스크립터 비트를 담고 나머지 두 옥텟은 바이트 수를 담습니다. 디스크립터 값 16은 블록이 재시작 마커를 실었다는 뜻입니다. 마커는 데이터 스트림에 삽입된 공백 없는 인쇄 가능한 문자열이었습니다. 사용자 데이터가 아니었고, TCP 시퀀스 번호에서 추론된 것도 아니었습니다. FTP는 복구 랜드마크를 양쪽 데이터 전송 프로세스가 모두 이해하는 표현 안에 의도적으로 배치했습니다.

이 선택이 재시작을 모드와 묶었습니다. RFC 1123은 나중에 그 결과를 명확히 말합니다: 초기 메커니즘은 마커를 데이터 스트림에 삽입할 수 있는 블록 또는 압축 모드를 필요로 했습니다. 빈도는 낮아도 되었습니다. 체크포인트가 매 블록마다 따라올 필요는 없었습니다.

이 기계 장치는 원시 네트워크 캡처만으로는 복구 상태가 부족한 이유도 설명합니다. 전송 프로세스는 송신자가 자신의 발신 표현을 어디서 재생성할 수 있는지, 수신자가 자신의 저장 표현을 어디서 재생성할 수 있는지 알아야 했습니다. 패킷 전달만으로는 어느 쪽의 로컬 사실도 제공하지 못했습니다.

수신자가 마커를 발행하기 전에 안정성이 먼저 왔다

RFC 1123에 따르면 마커를 받은 FTP 구현은rrrr를 인코딩하기 전에 이전 데이터 전부를 안정 저장소에 강제 기록해야 했습니다. 이 순서가 응답에 좁은 권위를 부여했습니다. 수신자는 단순히 “이 바이트들이 내 소켓을 통과했다”고 말한 것이 아닙니다. 그 앞 부분이 자신이 처리한다고 주장하는 중단 모델을 견딜 수 있는 위치를 식별한 것입니다.

안정이 전역적으로 영구하다는 뜻은 아니었습니다. RFC는 저장 매체, 복제 정책, 재해 복구 보증을 정의하지 않았습니다. 로컬 프로세스가 자신의 재시작 토큰이 진실로 남도록 이전 데이터를 충분히 내구적으로 만들 것을 요구했을 뿐입니다. 마커는 “여기로 재위치한다”가 무슨 뜻인지 아는 시스템에 속했습니다.

사용자 FTP는 이 짝을 보존할 것으로 기대되었습니다. RFC 1123은 재시작 제어 파일을 제안합니다: 전송 시작 시 비어 있게 만들고, 마커 짝이 도착하면 추가하며, 전송이 성공적으로 완료되면 삭제합니다. 그 작은 사이드카가 복구 장부였습니다. 클라이언트가 죽으면 최신 완전 짝—가장 큰 표시 카운터가 아니라—이 다음 시도의 안전한 후보였습니다.

삭제도 생성만큼 중요했습니다. 완료된 전송은 겉보기에 유효한 체크포인트를 서로 무관한 미래 파일에 남겨 두어서는 안 됩니다. 수명 주기가 의미의 일부였습니다: 시작 시 생성, 확정된 짝만 추가, 같은 중단된 전송에 소비, 성공 시 제거.

파일 위치에는 줄바꿈의 절반도 들어갈 수 있었다

왜 두 개의 불투명한 문자열이 필요했을까요? FTP가 네트워크 표현과 각 시스템의 저장 표현 사이에서 데이터를 변환할 수 있었기 때문입니다. 와이어 스트림의 위치가 항상 디스크의 같은 정수 위치에 대응하지는 않았습니다.

RFC 1123은 정확한 예제를 제공합니다. ASCII 전송에서 수신자는 네트워크 시퀀스 CRLF를 로컬 LF 하나로 바꿀 수 있습니다. 재시작 마커가 CR과 LF 사이에 떨어지면, 수신자는 CR을 이미 보고 버렸지만 줄바꿈 변환은 아직 끝내지 못한 상태입니다. 따라서 그rrrr값은 파일 위치뿐 아니라 “CR을 이미 봤다”는 상태까지 인코딩해야 했습니다. 그 상태 없이 정수 디스크 오프셋에서 재시작하면 문자를 더하거나 잃거나 중복할 수 있었습니다.

이것은 장식적 이기종성이 아니었습니다. RFC 959는 서로 다른 문자 코드, 워드 크기, 로컬 바이트 크기, 저장 규약을 가진 기계들을 다룹니다. FTP의 표현 유형, 파일 구조, 전송 모드가 별개의 매개변수인 이유는 “같은 파일”이 내부 배치가 같다고 가정하지 않고 이질적인 시스템을 건너야 했기 때문입니다.

따라서 마커는 불투명하면서도 정밀할 수 있었습니다. 그 이식성은 의도적으로 제한되어 있었습니다: 토큰을 생성한 시스템만 해석하면 되었습니다. 프로토콜은 보편적인 저장 좌표계가 아니라 대응 관계를 조율했습니다.

방향이 바뀌면 누가 어떤 토큰을 쥐는지도 바뀌었다

RFC 1123은 세 가지 경우를 다룹니다. 사용자→서버 전송에서는 사용자 측이ssss를 삽입하고, 서버는 이전 데이터를 확정하고rrrr를 생성해 짝을 돌려줍니다. 재개할 때 사용자는 자신의ssss로 자신을 재위치하고 서버에REST rrrr을 보냅니다.

서버→사용자 검색에서는 서버가 스트림 마커를 삽입합니다. 클라이언트는 자신의 로컬 복사본을 확정하고 대응하는 로컬 상태를 기록합니다. 나중에 클라이언트는 자신의 위치를 복원하고 서버의 마커를 REST로 돌려보냅니다.

서드파티 경우가 더 흥미로운 것을 드러냅니다. FTP는 하나의 사용자 프로세스가 두 서버 사이의 전송을 제어하는 것을 허용했습니다. 사용자는 절대 같은 파일 시스템 모델을 공유하지 않을 수도 있는 기계들에 속한 체크포인트 짝을 쥐게 됩니다. 재시작할 때 송신자에게는 송신자의 토큰만, 수신자에게는 수신자의 토큰만 보냈습니다.

클라이언트는 어느 좌표의 저자도 아니고 대응 관계의 보관인이었습니다. 이 분리는 조율자가 이해해야 할 것을 줄였습니다. 동시에 규율을 부과했습니다: 마커 짝은 전송 간에 섞이거나, 함부로 재정렬되거나, 잘못된 끝점이 해석될 수 없었습니다.

REST는 상태를 저장했을 뿐 전송을 수행하지 않았다

REST명령은 다음 서비스 명령을 위한 매개변수를 설정했습니다. 성공적인350응답은 서버가 마커를 저장했고 전송 명령을 기대한다는 뜻이었습니다. 파일 바이트가 하나라도 이동했다는 뜻, 부분 객체가 유효하다는 뜻, 완료가 성공할 거라는 뜻이 아니었습니다.

RFC 959의 상태 모델은 REST를 그 뒤의RETR,STOR또는APPE와 짝지었습니다. RFC 1123은 서로 다른 오류 의미를 추가합니다.554는 요청된 재시작 위치를 적용할 수 없다고 말할 수 있습니다.555는 현재 유형 또는 구조가 기존 파일과 일치하지 않는다고 말할 수 있습니다. 위치와 표현은 별개의 조건이며, 하나의 성공적 확인이 다른 하나를 조용히 충족시킬 수 없습니다.

이 두 명령 구조는 오래된 상태(stale state)도 만듭니다. 클라이언트가 재시작 마커를 설정한 뒤 의도한 전송 명령을 내지 못하면, 다음 작업이 목적이 사라진 지시를 상속받을 수 있습니다. 이후의 작업이 인접 규칙을 훨씬 명시적으로 만들었습니다.

STREAM 모드는 체크포인트를 산술로 좁혔다

RFC 3659가 FTP 확장을 문서화할 무렵에는 클라이언트와 서버가 보통의 STREAM 모드에서도 재시작을 원했습니다. 그 모드는 내장된 FTP 재시작 마커를 실지 않았습니다. 확장은 그래서 더 단순한 좌표—십진 옥텟—를 선택했습니다.

STREAM 모드에서REST 802816은 서버에게 바로 이어지는 전송의 처음 802,816옥텟을 보내지 말라는 뜻입니다. RFC의 예제는 이미지 유형을 설정하고, 서버 파일이 변경되지 않았음을 확인하고,350을 받은 뒤RETR을 발행합니다.REST 0은 재시작 효과를 제거하고 파일 전체를 요청합니다.

이 단순화는 이미지 모드 옥텟이 공통 좌표를 제공하기 때문에 강력했습니다. 짝지어진 마커 모델보다 의도적으로 좁기도 했습니다. 수치 형식은 수신자의 반쯤 끝난 문자 변환을 인코딩하지 않았습니다. 소스 버전을 식별하지 않았습니다. 클라이언트가 자신이 주장하는 접두어를 정확히 여전히 갖고 있다고 말하지도 않았습니다.

그리하여 RFC 3659는 시퀀스를 정확성의 일부로 만들었습니다. REST는 자신이 수정하는 전송 바로 앞의 마지막 명령이어야 합니다. 클라이언트가 그 전송 명령을 성공적으로 내지 못하면, 나중에 다시 시도하기 전에 REST를 다시 발행해야 합니다. 다음 전송을 처음부터 시작해야 한다면 명시적으로REST 0을 보내야 합니다.

구문과 실행 가능성은 서로 다른 시점에 실패할 수도 있습니다. 숫자가 아닌 STREAM 마커는 즉시 거부될 수 있습니다. 구문은 유효하지만 범위를 벗어난 마커는 뒤따르는 전송 명령이 파일과 작업 맥락을 제공할 때까지 거부되지 않을 수 있습니다. 좌표를 구문 분석하는 것은 좌표가 적용된다는 증명이 아닙니다.

저장 재개는 더 날카로운 경계를 가졌다

검색 재개는 조립 권한을 클라이언트에 남깁니다. 클라이언트는 돌려받은 접미어를 자신이 이미 쥔 접두어 옆에 놓거나, 겹치는 부분을 다시 받거나, 결과를 버릴 수 있습니다. 저장 재개는 서버에게 들어오는 옥텟을 기존 부분 객체에 기록하라고 요구합니다. 그러면 오래되거나 잘못된 오프셋이 더 파괴적인 힘을 갖게 됩니다.

RFC 3659는 의도된 용도를 이전에 실패한 전송을 완성하는 것으로 한정합니다. STOR의 경우, 재시작 마커가 서버가 이미 저장한 데이터의 끝에 있지 않으면 동작이 정의되지 않습니다. 이어지는 데이터가 수신지를 최소 이전 크기까지 늘리기에 부족해도 정의되지 않습니다. 서버가 REST 이후 APPE를 허용한다면, APPE는 맹목적으로 덧붙이는 것이 아니라 선택된 위치에서 STOR처럼 동작해야 합니다.

이 규칙들은 재시작 명령이 일반적인 스파스 파일 편집 인터페이스가 되는 것을 막습니다. 그렇다고 이어하기가 트랜잭션처럼 되는 것은 아닙니다. 실패한 두 번째 시도는 또 하나의 부분 파일을 남길 수 있습니다. 부분 수신지를 어떻게 명명하고, 보호하고, 검증하고, 제거할지는 운영자가 결정해야 합니다.

오프셋에는 여전히 객체에 대한 증거가 필요했다

완벽하게 구문 분석된 오프셋도 잘못된 버전을 가리킬 수 있습니다. 그리하여 RFC 3659는 재시작 전에 수정 정보를 확인할 것을 권고합니다. RETR의 경우, 클라이언트는 첫 전송 전에 서버 파일의 수정 시각을 얻고 이어하기 전에 다시 비교해야 합니다. STOR의 경우, 재개하려는 소스와 부분 수신지를 비교할 수 있습니다. MLST 팩트는 객체가 변경되었다는 더 강한 표시를 줄 수 있습니다.

이 경고는 조심스럽습니다. 클라이언트와 서버가 동기화된 시계를 공유할 필요는 없고, 시각 비교는 시계 오차를 허용해야 합니다. 수정 값은 최종 내용이 달라지는 것 외의 이유로 바뀔 수 있고, 내용은 바뀌었다가 나중에 돌아올 수도 있습니다. 이 증거는 무효화 신호이지 암호학적 신원이 아닙니다.

크기도 맥락에 의존합니다. RFC 3659는 현재 유형에서 REST에 적합한 전송 크기를 정의합니다. 반드시 범용 디스크 크기는 아닙니다. 일치하는 크기가 일치하는 바이트를 증명하지 않으며, 정확한 접두어와 접미어가 있어도 무결성이 중요하다면 파일 전체 검증이 여전히 필요합니다.

따라서 이 프로토콜은 재개를 최소 네 가지 주장으로 나눕니다: 기능이 지원된다, 마커 문법이 이해된다, 소스와 부분 수신지가 여전히 같은 전송에 속한다, 재구성된 결과가 정확하다.REST STREAM은 처음 두 가지만 직접 답합니다.

기능 광고는 약속이 아니라 능력을 이름 붙였다

RFC 3659의 STREAM 동작을 지원하는 서버는 FEAT을 통해REST STREAM을 광고합니다. 정확한 토큰은 클라이언트가 수치형 STREAM 확장을, 블록 또는 압축 모드에서만 가능한 재시작 지원과 구분하게 합니다.

현재IANA FTP 명령 및 확장 레지스트리는 이 구분을 보존합니다. 이 레지스트리는 기본REST를 RFC 959와 RFC 1123과 함께 나열하고, STREAM 모드에 대해 RFC 3659 및 FEAT 코드REST와 함께 수정된REST+항목을 나열합니다.

그 레지스트리는 표준화된 명령 계열을 기록합니다. FEAT은 구현 능력을 보고합니다. 어느 쪽도 특정 부분 파일을 식별하지 않고, 덮어쓰기를 승인하지 않고, 원격 버전이 변경되지 않았음을 증명하지 않으며, 오늘날 이 메커니즘이 얼마나 널리 배치되었는지도 측정하지 않습니다.

복구는 의미를 각자에게 국한함으로써 성공했다

FTP의 두 재시작 설계는 어색한 토큰이 상식적인 숫자로 대체된 단순한 이야기가 아닙니다. 각각은 서로 다른 표현 경계 안에서 상식적이었습니다.

초기 방식은 송신자와 수신자가 각자 자신의 상태를 서술했기 때문에 변환을 견딜 수 있었습니다. 프레임 전송 모드, 스트림 내 마커, 비동기 제어 응답, 유지된 짝 장부를 필요로 했습니다. 이후의 STREAM 방식은 지배적인 옥텟 스트림과 흔한 이미지 전송에 맞았습니다. 내장 마커를 없애고 재개를 표현하기 쉽게 만들었지만, 자신의 오프셋이 여전히 의도된 파일을 가리킨다는 것을 증명할 책임을 더 많이 클라이언트에게 넘겼습니다.

양쪽 모두에서 체크포인트의 권위는 완성된 객체보다 작았습니다. 끝점들에게 어디서 이어할 수 있는지 말해 주었을 뿐입니다. 파일을 누가 공급했는지 인증하지 않았고, 그 의미를 보증하지 않았으며, 조립 이후의 검증을 대신하지도 않았습니다.

출처와 증거의 한계

이 폐쇄된 출처들은 FTP의 명세된 재시작 메커니즘, 호스트 요구사항, 이후의 STREAM 확장, 명령 레지스트리를 확정합니다. 현재 제품 지원, 실제 배치, 전송 성공률, 특정 서버의 무결성 동작은 측정하지 않습니다. 따라서 이 글은 IANA 항목이나 FEAT 토큰을 실제 이어하기가 안전하다는 증거로 다루지 않습니다.