切分、校验并翻转标准报文头
한국어 원문으로 표시합니다.
목표
LH-STD 표준 헤더(80바이트)를 오프셋까지 이해하고, 파싱·검증·응답 생성·GUID 발급·스트림 분리를 직접 구현한다.
왜 중요한가
중계 계층은 헤더만 보고 판단한다. 헤더를 자르는 위치가 한 바이트만 어긋나도 라우팅·추적·중복 방지가 전부 엉뚱한 값을 본다. 그리고 전문은 TCP 스트림 위로 오므로, 길이 필드를 믿고 바이트로 자르는 습관이 없으면 긴 전문에서만 깨지는 버그를 운영에서 처음 만난다. 형식이 틀린 전문을 추측해서 처리하지 않고 E102 로 거절하는 것도 이 계층의 책임이다.
단계
- 정의서
/opt/lab/fixtures/eaimw/header/SPEC.md를 읽고/root/eaimw/header/layout.csv를 만든다. 머리글field,offset,length, 헤더 9개 필드를 순서대로, 오프셋은 0부터 센 바이트 위치. - 수신함
/opt/lab/fixtures/eaimw/header/inbox/의 모든 파일에 대해 전문길이 필드(앞 4바이트)와 실제 바이트 수(파일 크기 - 4)를 비교해/root/eaimw/header/lencheck.csv를 만든다. 머리글file,declared,actual,result, 파일 이름순, result 는OK또는LEN_MISMATCH. /root/eaimw/header/hdr.py를 만든다.python3 hdr.py <파일>이 헤더를 JSON 으로 출력하고(키: MSG_LEN·TX_CODE·GUID·SND_ORG·RCV_ORG·MSG_TYPE·RSP_CODE·SEND_TS·BODY_LEN, 값은 앞뒤 공백 제거, MSG_LEN·BODY_LEN 은 정수) 0 으로 끝난다. 정의서 5절의 형식 오류면 첫 줄에E102 <사유>를 출력하고 종료 코드 2 로 끝난다./root/eaimw/header/reply.py를 만든다.python3 reply.py <요청파일> <응답코드4자리>가 응답 전문을 표준출력(바이트)으로 낸다 — 거래코드·GUID 유지, 송수신 기관 맞바꿈, 구분 R, 응답코드 채움, 전송일시는 지금(한국 시각), 본문 없음, 전문길이 재계산. 응답코드가 4자리가 아니면 0 이 아닌 코드로 끝난다./root/eaimw/header/guid.py를 만든다. 실행할 때마다 소문자 16진수 32자(전부 0 금지) GUID 한 줄을 출력한다. 예측 가능한random이 아니라secrets나uuid로 발급한다./root/eaimw/header/split.py를 만든다. 전문 여러 개가 이어 붙은 파일(TCP 로 받은 바이트 그대로)을 받아 전문마다거래코드 GUID 본문바이트수한 줄을 출력하고 0 으로 끝난다. 마지막 전문이 잘려 있으면 완전한 것들을 먼저 출력한 뒤INCOMPLETE <남은바이트수>를 출력하고 종료 코드 3 으로 끝난다.- 수신함 전체를 판정해
/root/eaimw/header/report.csv를 만든다. 머리글file,tx_code,guid,result, 파일 이름순. 정상은OK, 거절한 전문은 tx_code·guid 를 비우고E102.
참고
- 바이트로 다루기: 파이썬은
open(f, "rb").read()로 읽고b[4:12].decode("ascii")로 자른다. 셸은head -c 4·stat -c %s. - 한글 한 글자는 EUC-KR 2바이트, UTF-8 3바이트다.
len("김하늘".encode("euc_kr"))는 6 이다. - 흔한 실수: 문자열로 디코드한 뒤에 길이를 세는 것. 전문길이는 바이트 수다.
- 흔한 실수: 형식이 틀린 전문을 추측해서 처리하는 것. 거절하고 이유를 남긴다.
- 사내 공통 라이브러리
/opt/lab/fixtures/eaimw/lib/lhstd.py는 2모듈부터 쓴다. 이 실습에서는 직접 만든다.
정의서를 오프셋으로 옮긴다
/opt/lab/fixtures/eaimw/header/SPEC.md 의 헤더 9개 필드를 /root/eaimw/header/layout.csv 로 옮긴다(field,offset,length, 오프셋은 0부터).
오프셋은 앞 필드들의 길이 합입니다. MSG_LEN 이 0·4 이면 TX_CODE 는 4 에서 시작합니다. 마지막 필드까지 더하면 80 이어야 합니다.
전문길이를 바이트로 대조한다
/opt/lab/fixtures/eaimw/header/inbox/ 의 모든 파일에 대해 선언 길이와 실제 길이를 비교해 /root/eaimw/header/lencheck.csv 를 만든다.
선언 길이는 head -c 4, 실제 길이는 stat -c %s 에서 4 를 뺀 값입니다. 한글이 든 파일을 편집기로 열어 세면 글자 수가 나옵니다 — 필요한 것은 바이트 수입니다.
파서를 만든다 — 틀리면 거절한다
/root/eaimw/header/hdr.py 가 헤더를 JSON 으로 출력하고, 형식 오류면 첫 줄 E102 와 종료 코드 2 로 거절한다.
open(f,'rb') 로 읽고 bytes 를 오프셋대로 자릅니다. 길이 대조·거래코드 정규식·GUID 소문자 16진수·기관 숫자 3자리·Q/R·datetime.strptime 으로 날짜 검증 — 정의서 5절 목록 그대로입니다.
요청을 뒤집어 응답을 만든다
/root/eaimw/header/reply.py <요청파일> <응답코드> 가 응답 전문을 표준출력으로 낸다.
3단계의 parse 를 import 해서 씁니다(from hdr import parse). 바이트를 내보낼 때는 print 가 아니라 sys.stdout.buffer.write 입니다. 전문길이는 나머지를 다 만든 뒤 len 으로 계산하세요.
GUID 를 발급한다
/root/eaimw/header/guid.py 가 실행할 때마다 소문자 16진수 32자 GUID 를 한 줄 출력한다(전부 0 금지, secrets 또는 uuid).
secrets.token_hex(16) 은 16바이트 난수를 16진수 32자로 줍니다. uuid.uuid4().hex 도 같은 모양입니다. 시각으로 만들면 같은 밀리초에 겹칩니다.
TCP 스트림을 전문으로 자른다
/root/eaimw/header/split.py 가 이어 붙은 전문을 길이 필드로 잘라 한 줄씩 출력하고, 잘린 꼬리는 INCOMPLETE 과 종료 코드 3 으로 알린다.
pos 를 0 에서 시작해 buf[pos:pos+4] 를 길이로 읽고 pos+4+길이 까지를 한 전문으로 자릅니다. 남은 바이트가 길이보다 모자라면 그것이 잘린 꼬리입니다.
수신함 판정 보고서
수신함 전체를 판정해 /root/eaimw/header/report.csv 를 만든다(file,tx_code,guid,result — OK 또는 E102).
3단계의 hdr.py 를 파일마다 돌려 종료 코드로 가릅니다. 거절된 전문의 거래코드를 억지로 읽어 적지 마세요 — 형식이 틀린 전문의 필드는 믿을 수 없습니다.