37. 협상된 세션 버전을 무시한 고정 레이아웃 파싱 (C#)
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 프로토콜 버전 협상 후, 세션별 버전에 맞춘 패킷 파싱
//
// 핸드셰이크에서 클라이언트와 서버는 사용할 프로토콜 버전을 협상하고, 그 결과를
// 세션에 저장한다(Session.NegotiatedVersion). 이동 패킷 레이아웃은 버전에 따라 다르다:
// v1 레이아웃: [seq:int32][tickMs:int32] (8바이트)
// v2 레이아웃: [seq:int32][tickMs:int32][inputFlags:int32] (12바이트, v2에서 필드 추가)
//
// 한 수신 버퍼에는 같은 연결에서 온 여러 패킷이 연이어 담길 수 있고, 파서는 오프셋을
// 전진시키며 순서대로 읽는다.
//
// 요구사항:
// - 각 세션의 협상된 버전에 맞는 레이아웃으로 파싱해야 한다(v1 클라는 inputFlags 없음).
// - 파서가 소비하는 바이트 수는 그 패킷의 실제 크기와 정확히 일치해야 한다
// (그래야 다음 패킷 경계가 맞는다).
//
// 아래 파서의 (A)(B) 지점을 검토하라.
using System;
public sealed class Session
{
public int NegotiatedVersion; // 핸드셰이크에서 정해져 저장됨 (1 또는 2)
}
public struct MoveInput { public int Seq; public int TickMs; public int InputFlags; }
public sealed class MovePacketParser
{
// buf[pos..] 에서 이동 패킷 하나를 읽고, pos 를 소비한 만큼 전진시킨다.
public MoveInput Parse(Session session, byte[] buf, ref int pos)
{
var m = new MoveInput
{
Seq = BitConverter.ToInt32(buf, pos),
TickMs = BitConverter.ToInt32(buf, pos + 4),
InputFlags = BitConverter.ToInt32(buf, pos + 8), // (A)
};
pos += 12; // (B)
return m;
}
} 결함 코드 · C++
// 시나리오: 프로토콜 버전 협상 후, 세션별 버전에 맞춘 패킷 파싱 (C++)
//
// 핸드셰이크에서 협상한 프로토콜 버전을 세션에 저장한다(Session::negotiatedVersion).
// 이동 패킷 레이아웃은 버전에 따라 다르다:
// v1: [seq:int32][tickMs:int32] (8바이트)
// v2: [seq:int32][tickMs:int32][inputFlags:int32] (12바이트, v2에서 필드 추가)
// 한 수신 버퍼에는 같은 연결에서 온 여러 패킷이 연이어 담기고, 파서는 오프셋을
// 전진시키며 순서대로 읽는다.
//
// 요구사항:
// - 각 세션의 협상 버전에 맞는 레이아웃으로 파싱한다(v1 클라는 inputFlags 없음).
// - 파서가 소비하는 바이트 수는 그 패킷의 실제 크기와 정확히 일치해야 한다.
//
// 아래 파서의 (A)(B) 지점을 검토하라.
#include <cstdint>
#include <cstring>
struct Session { int negotiatedVersion; }; // 1 또는 2 (핸드셰이크에서 저장)
struct MoveInput { int32_t seq; int32_t tickMs; int32_t inputFlags; };
class MovePacketParser {
public:
// data[pos..len) 에서 이동 패킷 하나를 읽고, pos 를 소비한 만큼 전진시킨다.
MoveInput parse(const Session& session, const uint8_t* data, std::size_t len, std::size_t& pos) {
MoveInput m{};
std::memcpy(&m.seq, data + pos + 0, 4);
std::memcpy(&m.tickMs, data + pos + 4, 4);
std::memcpy(&m.inputFlags, data + pos + 8, 4); // (A)
pos += 12; // (B)
return m;
}
};
int main() { return 0; } 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.