알라딘MGG와이드바


Protocol Buffer 로 C++ 과 C# 에서 데이터 읽기 개발 이야기

프로토콜 버퍼에 대한 기본 설명은 자바워크님의 블로그를 참고하자.

cpp 에서 프로토콜 버퍼를 사용하려면 다음과 같이 한다.
protobuf 프로젝트를 디버그, 릴리즈별로 따로 빌드한다.
addressbook.proto 와 protoc.exe 파일이 들어있는 폴더에서 ProtocolGen.bat 을 실행해 addressbook.pb.h, addressbook.pb.cc 파일을 만든 뒤 프로젝트에 추가한다. addressbook.proto 파일 내용은 다음과 같다.

package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}

ProtocolGen.bat 파일 내용은 다음과 같다.

set DST_DIR=D:\work\ProtocolBuffer\Test\PbTest4
set SRC_DIR=D:\work\ProtocolBuffer\Test\PbTest4
protoc -I=%SRC_DIR% --cpp_out=%DST_DIR% %SRC_DIR%/addressbook.proto

protobuf-2.5.0\protobuf-2.5.0\src 폴더를 include 에 추가하고, protobuf 를 빌드해서 나온 .lib 파일들(libprotobuf.lib)을 모아놓은 폴더를 lib 에 추가하고 해당 lib 를 Add 해 준다.(디버그 용을 위해 libprotobufd.lib 도 만들었다. link warning 을 막으려면 libprotobufd.pdb 도 생성해 준다.)

C++ 용 코드는 아래와 같다.

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>

using namespace std;
using namespace google;

int _tmain(int argc, _TCHAR* argv[])
{
// Message 객체에 값 세팅
tutorial::Person src_person;
src_person.set_id(41);
src_person.set_name("alice");
src_person.set_email("alice@anydomain.com");
tutorial::Person::PhoneNumber* phone0 = src_person.add_phone();
phone0->set_number("123-0101");
phone0->set_type(tutorial::Person_PhoneType_MOBILE);
tutorial::Person::PhoneNumber* phone1 = src_person.add_phone();
phone1->set_number("456-0202");
phone1->set_type(tutorial::Person_PhoneType_HOME);

// 미리 생성해야 하는 버퍼의 길이를 알아내어 버퍼할당
int bufSize = src_person.ByteSize();
char* outputBuf = new char[bufSize];

// 버퍼에 직렬화
protobuf::io::ArrayOutputStream os(outputBuf, bufSize);
src_person.SerializeToZeroCopyStream(&os);

// 버퍼에서 역직렬화
protobuf::io::ArrayInputStream is(outputBuf, bufSize);
tutorial::Person dst_person0;
dst_person0.ParseFromZeroCopyStream(&is);

// Message 객체에서 값 가져오기
string name = dst_person0.name();
int id = dst_person0.id();
for (int i=0;i<dst_person0.phone_size();++i)
{
const tutorial::Person_PhoneNumber& phone = dst_person0.phone(i);
tutorial::Person_PhoneType phone_type = phone.type();
string phone_number = phone.number();
}

// 파일에 직렬화
const char* test_filename = "person_in_cpp.txt";
fstream ofs(test_filename, ios::out | ios::trunc | ios::binary);
src_person.SerializeToOstream(&ofs);
ofs.close();

// 파일에서 역직렬화
fstream ifs(test_filename, ios::in | ios::binary);
tutorial::Person dst_person1;
dst_person1.ParseFromIstream(&ifs);
ifs.close();

string textFormatStr;
protobuf::TextFormat::PrintToString(src_person, &textFormatStr);
printf("%s\n", textFormatStr.c_str());

tutorial::Person dst_person2;
protobuf::TextFormat::ParseFromString(textFormatStr, &dst_person2);

// 메모리 해제
delete [] outputBuf;
outputBuf = NULL;
protobuf::ShutdownProtobufLibrary();

return 0;
}


C# 에서는 아래와 같은 방식으로 데이터를 읽는다.

먼저 [https]Google's Protocol Buffers project, ported to C# 에서 필요한 파일을 다운로드 받는다.
ProtocolGen.bat 에는 protogen addressbook.proto --proto_path=. 와 같이 입력한다.
같은 폴더에 protoc.exe, ProtoGen.exe, Google.ProtocolBuffers.dll, Google.ProtocolBuffers.Serialization.dll 가 있어야 한다.

정상적으로 실행되었다면 Addressbook.cs 파일이 만들어졌을 것이다.
CSharp CRT 프로젝트를 만든 뒤 Addressbook.cs 파일을 추가하고, Google.ProtocolBuffers.dll, Google.ProtocolBuffers.Serialization.dll 을 references 에 추가한다. 코드는 다음과 같다.

using System;
using System.IO;
using tutorial;

namespace PbTest3
{
class Program
{
static void Main(string[] args)
{
Person.Builder newPersonBuilder = Person.CreateBuilder();
newPersonBuilder.SetId(41)
.SetName("alice")
.SetEmail("alice@anydomain.com");
newPersonBuilder.AddPhone(
Person.Types.PhoneNumber.CreateBuilder()
.SetNumber("123-0101")
.SetType(Person.Types.PhoneType.MOBILE));
newPersonBuilder.AddPhone(
Person.Types.PhoneNumber.CreateBuilder()
.SetNumber("456-0202")
.SetType(Person.Types.PhoneType.HOME));

Person person = newPersonBuilder.Build();

// 버퍼에 직렬화
byte[] personByte = person.ToByteArray();

// 버퍼에서 역직렬화
Person person1 = Person.ParseFrom(personByte);

// Message 객체에서 값 가져오기
string name = person.Name;
int id = person.Id;
foreach (Person.Types.PhoneNumber pn in person.PhoneList)
{
Console.WriteLine(pn.Number);
}

// 파일에 직렬화
using (FileStream fs = new FileStream("person_in_csharp.txt", FileMode.OpenOrCreate))
{
person.WriteTo(fs);
}

// 파일에서 역직렬화
Person person2;
using (FileStream fs = new FileStream("person_in_cpp.txt", FileMode.Open))
{
person2 = Person.ParseFrom(fs);
}

// 텍스트 형식으로 출력
string textFormatStr = person2.ToString();
Console.WriteLine(textFormatStr);

// 문자열에서 parsing
//Person person3 = Person.ParseFromString(textFormatStr); // 없는건가?
}
}
}

핑백

덧글

댓글 입력 영역


Yes24위대한게임의탄생3

위대한 게임의 탄생 3
예스24 | 애드온2