개요
Zmodem은 1980년대 후반에 개발된 효율적인 파일 전송 프로토콜로, 직렬 통신 환경에서 신뢰성 있고 빠른 데이터 전송을 목표로 합니다. 이 프로토콜은 양방향 제어 신호를 사용하지만 실제 데이터는 단방향으로 흐르며, 오류 복구, 재전송, 스트리밍 최적화 기능을 제공합니다.기본적인 전송 구조는 다음과 같습니다:
[보내는 측] ----(데이터 채널)----> [받는 측]
<----(제어 채널)-----
모든 통신은 **프레임**(frame) 단위로 구성되며, 각 프레임은 헤더와 선택적으로 데이터 조각(subpacket)으로 이루어집니다.
프레임 형식
Zmodem은 세 가지 형태의 프레임 인코딩을 지원합니다:- HEX (16진수): ASCII 문자만 사용. 주로 제어 채널에서 사용.
- BIN16: 바이너리 데이터 + 16비트 CRC 보호.
- BIN32: 바이너리 데이터 + 32비트 CRC 보호 (높은 신뢰성).
HEX 프레임 형식
ZPAD ZPAD ZDLE ZHEX [타입] [정보x4] [CRC1] [CRC2] CR LF [XON]- 모든 값은 두 자리 16진수 문자열로 인코딩됨. - 대문자 허용 안 됨. - XON은 ZACK/ZFIN 외 모든 프레임에 포함되어 흐름 제어를 보장함.
BIN16 / BIN32 프레임 형식
ZPAD ZDLE [스타일] [타입] [정보x4] [CRC...]- BIN16: 스타일 = 'A' (0x41) - BIN32: 스타일 = 'C' (0x43) - 정보 필드 이후 데이터 조각이 올 수 있음.
헤더 구조
모든 프레임은 공통 헤더를 포함하며, 다음 요소로 구성됩니다:- 프레임 타입: 1바이트, 동작 유형 식별.
- 정보 필드: 4바이트 (P0~P3), 오프셋 또는 플래그 포함.
- CRC: 무결성 검사를 위한 체크섬 (16비트 또는 32비트).
ZRINIT 프레임은 수신기가 초기화되었음을 알리고, 지원하는 기능들을 비트 플래그로 전달합니다.
주요 프레임 타입
| 타입 | 값 | 방향 | 용도 |
|---|---|---|---|
| ZRQINIT | 0x00 | S→R | 수신기 초기화 요청 |
| ZRINIT | 0x01 | R→S | 수신기 기능 보고 |
| ZFILE | 0x04 | S→R | 파일 메타데이터 전송 |
| ZDATA | 0x0A | S→R | 실제 파일 데이터 전송 시작 |
| ZEOF | 0x0B | S→R | 파일 전송 종료 알림 |
| ZRPOS | 0x09 | R→S | 특정 위치에서 재전송 요청 |
| ZFIN | 0x08 | S→R | 세션 종료 요청 |
데이터 조각 (Subpacket)
ZDATA와 같은 프레임은 하나 이상의 데이터 조각을 포함할 수 있습니다. 각 조각은 다음과 같은 구조를 가집니다:[데이터...] ZDLE [종류] [CRC]여기서
ZDLE는 0x18로, 특수 제어 시퀀스의 시작을 나타냅니다. 실제 데이터 내에 0x18이 포함될 경우, ZDLEE(0x58)로 이스케이프 처리됩니다.
주요 데이터 조각 종류
- ZCRCW: "Wait" — 수신 측이 응답(ZACK)을 보내야 함. 버퍼 정리를 위해 사용.
- ZCRCE: "End" — 오류 발생 시에만 응답.
- ZCRCQ: "Query" — 비동기 응답 요구 (전이중 모드에서 사용).
- ZCRCG: "Go" — 오류 없으면 계속 전송.
이스케이프 인코딩 (ZDLE)
통신 중 제어 문자와 데이터 충돌을 방지하기 위해 Zmodem은 **ZDLE 인코딩**을 사용합니다. 특정 바이트 값은 전송 전 변환되며, 수신 측에서 복원됩니다.다음은 대표적인 이스케이프 시퀀스입니다:
0x18 → 0x18 0x58 // ZDLE itself 0x10 → 0x18 0x50 // DLE 0x11 → 0x18 0x51 // XON 0x13 → 0x18 0x53 // XOFF 0x7F → 0x18 0x6C // RUBOUT (DEL) 0xFF → 0x18 0x6D // RUBOUT (extended)또한, Telenet과 같은 오래된 네트워크 호환성을 위해
CR @ CR 시퀀스도 보호됩니다.
세션 흐름
초기화
- 송신자는
ZRQINIT전송. - 수신자는
ZRINIT응답, 기능 플래그 포함. - 필요 시
ZSINIT으로 추가 설정 교환. - 수신자는
ZACK으로 확인.
파일 전송
- 송신자는
ZFILE+ 파일 메타데이터 전송. - 수신자는 필요 시
ZSKIP으로 건너뛸 수 있음. - 수신자는
ZRPOS로 시작 오프셋 지정 (재시작 지원). - 송신자는
ZDATA프레임으로 데이터 전송 시작. - 수신자는 정기적으로
ZACK또는ZRPOS로 상태 피드백. - 파일 종료 시
ZEOF전송.
세션 종료
- 송신자는
ZFIN전송. - 수신자는
ZFIN응답. - 송신자는 "OO" 문자열 전송 후 종료.
- 양측 연결 종료.
파일 메타데이터 (ZFILE)
ZFILE 프레임 다음에는 NUL 문자로 구분된 문자열 조각이 옵니다:
[경로명]\0[크기]\0[수정일]\0[모드]\0[남은 파일 수]\0\0- 경로명: 절대 경로 금지, 디렉터리 구분자는 '/' 사용. - 크기: 10진수 문자열. - 수정일: UNIX 타임스탬프 (1970년 기준 초 단위). - 모드: 일반적으로 Unix 권한 (8진수), 비유닉스 시 0. - 남은 파일 수: 배치 전송 시 예상 갯수. 메타데이터 전체 길이는 1024바이트를 초과할 수 없음.
오류 및 복구
- 손상된 프레임: 수신자는ZNAK 전송.
- 위치 불일치: 수신자는 ZRPOS로 올바른 오프셋 요청.
- 재시작 가능: 이전에 중단된 전송은 ZRPOS를 통해 이어서 진행 가능.
- 연결 끊김: 5회 연속 CAN(0x18) 수신 시 강제 종료.
보안 고려사항
ZCHALLENGE는 간단한 난수 검증 메커니즘을 제공하지만, 암호학적으로 안전하지 않음. 현재 환경에서는 의존하지 않는 것이 좋습니다. 대신, 전송 전 인증이나 암호화 계층(예: SSH)을 사용해야 합니다.
상수 정의
#define ZPAD 0x2A // 프레임 시작 패딩 #define ZDLE 0x18 // 이스케이프 문자 #define ZBIN 0x41 // BIN16 프레임 #define ZHEX 0x42 // HEX 프레임 #define ZBIN32 0x43 // BIN32 프레임 #define ZRQINIT 0x00 #define ZRINIT 0x01 #define ZFILE 0x04 #define ZDATA 0x0A #define ZEOF 0x0B #define ZFIN 0x08 #define ZRPOS 0x09