DUJINLABS.COM

전자회로 실무 / 펌웨어

시리얼 수신에서는 배열(array) 용량과 실제 받은 길이를 따로 관리합니다

시리얼 데이터를 받은 뒤 엉뚱한 변수가 바뀐다면 버퍼(buffer)를 넘겨 썼을 수 있습니다. 받을 데이터 길이가 저장 공간을 넘지 않는지 확인하고, 실제로 받은 길이만큼만 처리해야 합니다.

먼저 알아둘 용어

바이트(byte)·배열(array) 용량 — 바이트는 여기서 8비트의 저장 단위입니다. 배열 용량은 쓸 수 있는 바이트 수이며, 외부에서 받은 길이 요청이 그 공간을 늘려 주지는 않습니다.

NUL(Null Character)·바이너리(binary) — NUL은 값이 0인 바이트로, C 문자열에서는 끝을 표시합니다. 바이너리 데이터에서는 0도 내용의 일부일 수 있어 문자열 함수로 처리하면 잘릴 수 있습니다.

타임아웃(timeout)·메시지(message) 경계 — 타임아웃은 기다릴 수 있는 최대 시간입니다. 메시지 경계는 하나의 데이터 묶음이 끝나는 위치이며 고정 길이·길이 필드·구분자 등으로 정합니다. 시간 초과가 정상 메시지의 끝이라는 뜻은 아닙니다.

문자를 차례로 저장한 뒤 문자열 끝에 NUL을 넣는 예입니다. 바이너리 데이터에는 별도 길이가 필요합니다. 재생 속도와 움직임의 크기는 설명을 위한 것입니다.
정지 그림 확대
문자를 차례로 저장한 뒤 문자열 끝에 NUL을 넣는 예입니다. 바이너리 데이터에는 별도 길이가 필요합니다. 재생 속도와 움직임의 크기는 설명을 위한 것입니다. · 그림을 클릭하면 확대됩니다.

요청한 길이가 저장 공간을 넘지 않는지 확인합니다

char buffer[10]Serial.readBytes(buffer,20)을 호출하면 함수가 최대 20바이트를 쓰려는 동안 10바이트 배열 밖의 메모리를 손상시킬 수 있습니다. 목적지 용량을 늘리거나 요청 길이를 줄여 관계를 맞추어야 합니다. 배열을 늘리는 것만으로 메시지가 항상 완전히 도착하는 것은 아닙니다.

함수의 약속을 확인합니다

Arduino AVR 계열의 readBytes는 요청 길이만큼 읽거나 타임아웃이 발생하면 멈추고 실제로 받은 바이트 수를 반환합니다. 문자열 끝의 NUL은 자동으로 붙이지 않습니다. 따라서 용량, 반환 길이, 종단 문자 처리를 각각 확인해야 합니다. 다른 코어(core)·라이브러리(library)의 함수는 같은 이름이어도 구현과 약속을 확인합니다.

고정 길이 20바이트의 바이너리라면 최소 20바이트의 목적지가 필요합니다. 수신 뒤에는 반환 길이가 20인지 확인하고, 짧게 들어왔다면 미완성 데이터로 처리합니다. 바이너리를 문자열 출력 함수에 넘기지 않습니다. 데이터 안의 0바이트는 내용의 일부일 수 있습니다.

문자열로 다룰 최대 20바이트의 본문이라면 끝 표시용 공간을 하나 더 확보합니다. 다음 예는 최대 20바이트를 읽고 실제 받은 길이 바로 뒤에 종단 문자를 놓습니다.

char text[21];
size_t n = Serial.readBytes(text, sizeof(text) - 1);
text[n] = '\0';

이 코드는 메모리 끝을 넘기지 않고 종단할 공간을 남기지만, 메시지 경계를 자동으로 이해하지는 않습니다. 반환값이 짧을 수 있고, 내장된 NUL이 있다면 일반 문자열 처리에서 그 뒤가 보이지 않을 수 있습니다. “안전한 배열”과 “올바른 프로토콜 메시지”를 구분합니다.

입력을 사용하기 전에 길이와 형식을 검증합니다

수신 형식을 고정 길이, 길이 필드, 구분자 중 무엇으로 정할지 먼저 확인합니다. 외부 데이터가 알려 준 길이를 그대로 readBytes에 넘기지 않습니다. 수신 길이가 버퍼의 남은 공간과 프로토콜에서 허용하는 최대 길이를 모두 넘지 않는지 검사합니다. 거부한 데이터가 다음 메시지의 시작으로 잘못 처리되지 않도록 재동기화 규칙도 정합니다.

타임아웃은 손상된 연결에서 무한히 기다리지 않게 하지만 제어 작업을 늦출 수 있습니다. 바깥 루프(loop)를 경과 시간 검사로 구성해도 수신 함수 안에서 길게 기다리면 반응은 늦습니다. 필요한 응답 시간에 맞춰 짧게 읽어 누적하고, 현재까지 받은 길이와 메시지 완성 상태를 별도로 관리할지 결정합니다.

시험 입력확인할 결과
0바이트·일부만 도착실제 길이를 사용하고 이전 데이터가 섞이지 않음
정확한 최대 길이배열 끝과 종단 공간을 넘지 않음
최대보다 긴 입력거부·버림·다음 경계 처리 방식이 명확함
잘못된 길이 필드·내장 NUL형식 검증에서 구별됨
입력이 중간에 끊김타임아웃과 루프 지연이 요구 범위 안임

수신 값이 그럴듯하다는 이유로 성공 처리하지 않습니다. 실제 반환 길이와 메시지 형식을 통과한 데이터만 후단에서 사용합니다. 최대 길이뿐 아니라 0바이트, 부분 수신, 중간 끊김, 과도한 길이와 다음 메시지 복구까지 시험해야 배열과 프로토콜의 검증이 연결됩니다.

작업 순서를 다시 확인합니다

시리얼 수신에서는 배열 용량과 실제 받은 길이를 따로 관리합니다 — 설명용 도해
시리얼 수신에서는 배열 용량과 실제 받은 길이를 따로 관리합니다 — 설명용 도해 · 클릭하면 확대됩니다.