31. 프레임 무결성 검증(체크섬/CRC) 부재
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// [시나리오] 길이 프리픽스 프레임 수신 (서버-클라)
// 프레임 포맷: [4바이트 길이(len, payload 바이트 수)][2바이트 msgType][len-2 바이트 payload]
// 이 서버는 TCP 스트림에서 프레임을 잘라 msgType 에 따라 페이로드를 해석한다.
// 전송 구간에는 방화벽/프록시, 불안정한 무선 구간, 또는 악의적 중간자가 있을 수 있어
// 프레임 바이트가 전송 중 손상되거나 조작될 가능성이 있다.
//
// [요구사항]
// - 손상되거나 조작된 프레임은 유효한 것으로 처리되어서는 안 된다.
// - 한 프레임이 손상되어 거부되더라도, 이후 수신 스트림의 프레임 동기화(경계 인식)는
// 유지되어야 한다(다음 정상 프레임을 정상적으로 계속 처리할 수 있어야 한다).
//
// [과제] FrameReader.TryReadFrame 을 검토하고, 전송 중 프레임 일부가 손상/조작되었을 때
// 위 요구사항이 어떻게 어긋날 수 있는지 원인과 수정안을 제시하라.
// 표시된 (A)(B) 지점에 주목하라.
using System;
class FrameReader
{
private byte[] _buf = new byte[64 * 1024];
private int _len; // _buf 안에 쌓인 유효 바이트 수
public void OnBytesReceived(byte[] data, int count)
{
Array.Copy(data, 0, _buf, _len, count);
_len += count;
}
// 완전한 프레임이 있으면 payload 를 반환하고 true, 아니면 false.
public bool TryReadFrame(out ushort msgType, out ArraySegment<byte> payload)
{
msgType = 0;
payload = default;
if (_len < 6)
return false;
int frameLen = BitConverter.ToInt32(_buf, 0); // (A)
if (_len < 4 + frameLen)
return false; // 아직 다 안 옴
msgType = BitConverter.ToUInt16(_buf, 4);
payload = new ArraySegment<byte>(_buf, 6, frameLen - 2);
// (B)
int consumed = 4 + frameLen;
Array.Copy(_buf, consumed, _buf, 0, _len - consumed);
_len -= consumed;
return true;
}
} 결함 코드 · C++
// [시나리오] 길이 프리픽스 프레임 수신 (서버-클라)
// 프레임 포맷: [4바이트 길이(len, payload 바이트 수)][2바이트 msgType][len-2 바이트 payload]
// 이 서버는 TCP 스트림에서 프레임을 잘라 msgType 에 따라 페이로드를 해석한다.
// 전송 구간에는 방화벽/프록시, 불안정한 무선 구간, 또는 악의적 중간자가 있을 수 있어
// 프레임 바이트가 전송 중 손상되거나 조작될 가능성이 있다.
//
// [요구사항]
// - 손상되거나 조작된 프레임은 유효한 것으로 처리되어서는 안 된다.
// - 한 프레임이 손상되어 거부되더라도, 이후 수신 스트림의 프레임 동기화(경계 인식)는
// 유지되어야 한다(다음 정상 프레임을 정상적으로 계속 처리할 수 있어야 한다).
//
// [과제] FrameReader::tryReadFrame 을 검토하고, 전송 중 프레임 일부가 손상/조작되었을 때
// 위 요구사항이 어떻게 어긋날 수 있는지 원인과 수정안을 제시하라.
// 표시된 (A)(B) 지점에 주목하라.
#include <cstdint>
#include <cstring>
#include <vector>
class FrameReader {
std::vector<uint8_t> buf_ = std::vector<uint8_t>(64 * 1024);
size_t len_ = 0; // buf_ 안에 쌓인 유효 바이트 수
public:
void onBytesReceived(const uint8_t* data, size_t count) {
std::memcpy(buf_.data() + len_, data, count);
len_ += count;
}
// 완전한 프레임이 있으면 payload 포인터/길이와 msgType 을 채우고 true, 아니면 false.
bool tryReadFrame(uint16_t& msgType, const uint8_t*& payload, size_t& payloadLen) {
if (len_ < 6) return false;
int32_t frameLen;
std::memcpy(&frameLen, buf_.data(), 4); // (A)
if (len_ < static_cast<size_t>(4 + frameLen))
return false; // 아직 다 안 옴
std::memcpy(&msgType, buf_.data() + 4, 2);
payload = buf_.data() + 6;
payloadLen = static_cast<size_t>(frameLen - 2);
// (B)
size_t consumed = 4 + static_cast<size_t>(frameLen);
std::memmove(buf_.data(), buf_.data() + consumed, len_ - consumed);
len_ -= consumed;
return true;
}
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.