컴퓨터 프로그래밍에서 마샬링(Marshalling) 이란, 한 프로세스의 메모리에 존재하는 객체나 구조체, 혹은 복잡한 데이터 구조를 다른 환경에서도 해석하고 사용할 수 있도록 표준화된 형태로 변환하는 과정을 의미합니다. 이는 단순한 데이터 변환이 아니라, 데이터가 원래 포함하고 있던 의미와 구조를 유지하면서도 서로 다른 시스템, 언어, 런타임, 메모리 모델 간에 안전하게 전달할 수 있도록 ‘운반 가능한 형태’로 재구성하는 작업이라고 할 수 있습니다.
예를 들어, 하나의 프로그램 안에서 사용하는 객체나 구조체는 내부 메모리 주소, 포인터, 정렬 방식(Alignment), 엔디안(Endianness) 등 그 프로그램의 실행 환경을 그대로 반영합니다. 그러나 이러한 내부 표현은 다른 프로세스나 다른 언어, 혹은 네트워크를 통해 데이터를 받아야 하는 외부 시스템에서는 제대로 이해할 수 없습니다. 따라서 데이터를 전송하거나 공유하기 위해서는 내부 메모리 구조를 그대로 전달하는 것이 아니라, 서로 다른 환경에서도 동일하게 해석될 수 있는 형식으로 바꿔야 합니다.
이런 이유로 마샬링은 프로세스 간 통신(IPC), 네트워크를 통한 데이터 전송, 원격 함수 호출(RPC), 언어 경계를 넘는 함수 호출(C ↔ Python, C# P/Invoke, Swift ↔ C 등) 같은 상황에서 필수적인 역할을 수행합니다. 이러한 환경에서는 서로 다른 메모리 구조나 데이터 표현 방식을 가진 시스템끼리 데이터를 주고받기 때문에, 데이터의 무결성과 의미를 보존하기 위해 반드시 일관된 변환 과정이 필요합니다.
따라서 마샬링은 단순히 데이터를 직렬화하는 행위를 넘어, 서로 다른 시스템 간의 호환성을 보장하고 안전한 데이터 이동을 실현하기 위한 핵심 기술이라고 할 수 있습니다. 이는 현대의 분산 시스템, 네트워크 프로그래밍, 크로스-플랫폼 개발에서 없어서는 안 될 중요한 개념입니다.
1. 마샬링(Marshalling)의 개요
마샬링 = 데이터를 직렬화(Serialize)하고, 전송 가능한 형식으로 패키징하는 과정
즉,
프로세스 A의 메모리에 있는 구조체 → 네트워크로 보내기 위해 byte buffer로 변환
- C# 객체 → Unmanaged C API 구조체로 변환
- JSON/XML로 데이터를 변환
- RPC(Remote Procedure Call)에서 함수 파라미터를 변환
- COM interop, JNI, C# P/Invoke 등 언어 경계를 넘길 때 변환
이와 같이 원래의 메모리 레이아웃 그대로는 다른 환경에서 해석할 수 없는 데이터를 “안전한 형태”로 만드는 것이 마샬링입니다.
2. 왜 마샬링이 필요한가?
▶ 이유 1: 다른 시스템은 메모리 구조를 공유하지 않음
예: 프로세스 A 안의 C 구조체는 프로세스 B에서 그대로 읽을 수 없음
▶ 이유 2: 언어/플랫폼마다 데이터 표현 방식이 다름
-
C: null-terminated string (char*)
-
Python: length-prefixed Unicode string
-
C#: UTF-16 string
-
Java: UTF-16 String 객체
▶ 이유 3: 엔디안(Endianness) 차이
-
x86 → Little Endian
-
네트워크 → Big Endian
따라서 전송 전에 변환해야 함.
3. 직렬화(Serialization)와의 차이
직렬화(Serialization)와 마샬링(Marshalling)은 모두 데이터를 다른 형태로 변환한다는 공통점이 있지만, 목적과 적용 범위에서 중요한 차이를 가진다. 직렬화는 데이터를 파일로 저장하거나 네트워크로 전송하기 위해 객체나 데이터 구조를 단순한 바이트 스트림(byte stream) 형태로 변환하는 과정을 의미한다. 주로 JSON, Protobuf, BinaryFormatter처럼 특정 형식으로 변환하여 저장하거나 전송하는 데 초점이 맞춰져 있다.
반면 마샬링은 이보다 더 포괄적인 개념으로, 서로 다른 언어, 프로세스, 런타임 환경 사이에서 데이터가 올바르게 해석될 수 있도록 구조와 의미를 유지한 채 변환하는 과정을 말한다. 이 과정에서는 단순한 데이터 변환뿐 아니라, 타입 정보나 구조적 메타데이터까지 포함하여 전체 객체를 타 환경에서도 그대로 사용할 수 있도록 정교하게 변환되는 것이 일반적이다. 이러한 특성 때문에 COM 인터페이스, .NET Interop, 원격 프로시저 호출(RPC) 등 이질적인 시스템 간 데이터 교환이 필요한 곳에서 필수적으로 사용된다.
이처럼 마샬링은 직렬화를 포함하는 더 넓은 개념으로, 단순히 데이터를 바이트 형태로 만드는 것 이상의 목적을 수행하며, 이기종 환경 간의 데이터 호환성과 구조적 일관성을 보장하기 위한 보다 확장된 변환 기술이라고 볼 수 있다.
마샬링은 직렬화보다 더 넓은 개념입니다.
4. 마샬링의 사례
C#에서 C DLL 호출할 때
[DllImport("user32.dll")]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
C#의
string → C의 char* UTF-8/UTF-16 변환 → 이것이 바로 마샬링COM Interop
COM 객체에서 BSTR 문자열을 사용
C/C++에서는 wchar_t*, length 포함
.NET에는 System.String → 변환 작업이 자동 마샬링으로 처리됨
네트워크 통신
구조체를 그대로 socket에 보내면 안 됨
→ 패킹(packing), 엔디안 변환, alignment 조정 필요
typedef struct {
int id;
float value;
} Packet;
전송 전:
-
4바이트 정렬 문제 해결
-
엔디안 변환
-
byte array로 변환
이 과정이 마샬링.
원격 함수 호출(RPC / gRPC / WebRPC)
서버에서 원격 함수 호출 시,
파라미터·리턴값을 네트워크로 보내기 위해
JSON/Protobuf 형식 변환 → 마샬링
파라미터·리턴값을 네트워크로 보내기 위해
JSON/Protobuf 형식 변환 → 마샬링
마샬링 과정 예시 (C → C#)
C 구조체
typedef struct {
int id;
char name[32];
} User;
C#에서 사용하려면:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct User {
public int id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string name;
}
}
여기서 MarshalAs가 마샬링을 정의하는 부분임.
언마샬링(Unmarshalling)
마샬링의 반대 과정 → 네트워크로 받은 byte buffer → 원래의 구조체로 복원
Marshalling = 구조체 → byte stream
Unmarshalling = byte stream → 구조체