hello world 2014. 1. 14. 18:56

Google Protocol Buffer 사용해보기 - 개정판

저번에 너무 대충 쓴거 같아서 차근차근 해볼수 있도록 다시 올려봅니다.


우선 소스를 받습니다. ( https://code.google.com/p/protobuf/ )

까보면 대충 폴더가 이렇습니다.


vsproject 폴더에서 protobuf.sln 파일을 찾아서 visual studio 같은걸로 빌드해줍니다.


debug 나 release 든 폴더에 protoc.exe 파일이 생성됩니다. 이걸로 .proto 파일을 .h 와 .cc 로 만들어 주게 됩니다.

 
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;
}


옵션을 잘 골라서 이전에 만든 proto 파일을 잘 역어주면... pb.cc 파일 과 pb.h 파일이 생성 됩니다.

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/test.proto

이라고 tutorial page 에 되어있습니다만 저는 .bat 파일 만들어서 실행하고 있습니다.

del .\output\*.h

del .\output\*.cc

for %%a in (*.proto) do protoc.exe -I=. -I=../../protobuf-2.5.0/src --cpp_out=./output/ %%a

pause

사용할 때는 Directory 와 lib 파일을 설정해야 합니다.

1. Include path : protobug-2.5.0/src


 2. library path : 아까 build한  output 폴더 


 3. library file : libprotobuf.lib



이제 사용할 일만 남았어요


myfile 이라는 파일에 fstream 을 이용해서 저장하고, 다시 파일에서 일거와서 메모리에 가져와서 출력해 보겠습니다.


우선 include 부터 하고

 #include "test.pb.h" 


쓰기.

Person person;                      // proto 에서 저장한 객체를 사용 할 수 있습니다.
person.set_name("John Doe");        // 기본적으로 set_이름, get_이름 을 사용할 수 있습니다.
person.set_id(1234);
person.set_email("123@test.com");

fstream _output( "myfile", ios::out | ios::binary);   
person.SerializeToOstream(&_output);        // myfile 이란 파일에 바로 써버립니다.
_output.close();


읽기.

fstream input( "myfile", ios::in | ios::binary );  // myfile 이란 파일에서 읽습니다.
Person personReadMsg;
PersonReadMsg.ParseFromIstream(&input);
cout << "Name: " << personReadMsg.name() << endl 
       << "Email : " << personReadMsg.email() << endl;


결과 .



간단하게는 이렇게 써볼 수 있습니다.

실제로는 SerializeToString 이라던지 SerializeToArray 함수를 이용해서 소켓 버퍼에 써서 통신하고 있습니다.


한가지 특이한 점?은 동적으로 스키마를 만들 수 있습니다.

DynamicMessageFactory 를 찾아 보시면 됩니다. - 나중에 시간되면 알아보는걸로..


이걸가지고 뭘 하냐면, 클라이언트에서는 proto 파일을 갖고 있지않고, 서버에서 보내준 스키마를 사용합니다.

서버로 부터 받은 스키마를 통해 xml 로 Parsing 해서 가공해서 사용하고 있습니다.


ps : 저번에 쓴글에 오류가 많아서 다시한번 protobuf 에 대해서 써봤습니다. 지난글은 잊어주세요 ㅋㅋㅋ

In to the C# 2014. 1. 14. 11:58

Google Protocol Buffer 사용해보기 with C# - 세번째

Protocol Buffers는 C#만을 위한 라이브러리는 아닙니다.

Protocol Buffers - Developer guide를 보면 C++, Java, Python에 대해서만 설명을 해줍니다. C#은 third party로 분류 되어 있구요.


사실 third-party로 분류된 언어는 많습니다. 

https://code.google.com/p/protobuf/wiki/ThirdPartyAddOns


위 주소로 방문하시면 아시겠지만 Action Script, Go, D, 얼랭, 루아, 펄, 루비, 스칼라, PHP...헉헉..

많네요.


하지만 본인의 주력 언어는 C#이니까!


제가 세번째 글을 포스트 하는 이유는 C#으로 proto 파일을 만들어 내는 방법을 소개해 드리려 합니다.

C#으로 클래스 구현해놓고 타언어 지원을 위해 proto파일을 직접 만들려고 하면 오류도 생길 수 있고, 귀찮고, 위험하잖아요.


소스는 아래와 같습니다.


class 선언한 곳은 기존 예제와 다를 바 없으니 패스 하시고..

가장 아래 메소드 ProtoFileWrite를 보시겠습니다.


실행파일 폴더에서 proto 폴더를 만든 후

파일 저장 Path를 만들고..

Line 62번째!!

GetProto 일반화 메소드가 있습니다! proto파일을 만들려고 하는 타입을 넘겨주면 프로토 파일을 만들어 줍니다.


proto 파일이 어떻게 생성되었는지 보겠습니다.

위 내용은 Packet.proto입니다.



위 내용은 Test.proto입니다.


어때요? 참쉽죠?ㅋ


이렇게 ProtoBuf-net 에 대해서 알아봤습니다.

사실 ProtoBuf-net에는 많은 기능들이 있는데 전부 알아보지는 못했네요. 아쉽지만 나중에 좋은 꼼수들을 알게 될 경우 포스트 할께요~

'In to the C#' 카테고리의 다른 글

Delegates와 Serialization  (0) 2014.01.17
Dispose in C#  (0) 2014.01.14
Thread Pool과 Task  (0) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 두번째  (1) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 첫번째  (0) 2014.01.13
In to the C# 2014. 1. 14. 11:14

Google Protocol Buffer 사용해보기 with C# - 두번째

C#에서 ProtoBuf-net을 사용한다는 것은 굉장히 쉽고, 머리아픈 것들을 한방에 날려버립니다.

다른 언어로 개발된 어플리케이션과 데이터를 주고 받을 때도 문제가 없으며, 제너레이터, proto파일 등을 생각할 필요도 없구요. 다만 약간의 단점도 있습니다. 그것은 패킷에 대한 사이즈를 개발자가 직접 컨트롤 할 수가 없다는 것입니다. (아! 이 것은 ProtoBuf-net의 단점이 아니라 Protocol Buffers의 전반적인 내용입니다!!)


가령 int32형 데이터를 하나 보내는데도 4바이트 이상을 소모할 수가 있다는 것입니다. 하지만, 반대로 size가 줄어들 수도 있습니다.


소스를 보시면 총 4번의 직렬화 결과를 얻었습니다.


Line 19 ~ 23은 SizeTest 인스턴스의 key값이 0일 때, 

Line 25 ~ 29은 SizeTest 인스턴스의 key값이 1일 때,

Line 31 ~ 35은 SizeTest 인스턴스의 key값이 int형 min value일 때,

Line 37 ~ 41은 SizeTest 인스턴스의 key값이 int형 max value일 때 입니다.


결과는 아래와 같습니다.



헐!

대박!


같은 int형의 값이라도 byte 배열의 길이가 달라졌네요;;;

값이 0일 때는 제로배열!!

값이 1일 때는 2Byte

int형 min value 일때는 11Byte 씩이나??

int형 max value 일때는 6Byte 이군요!


사실 이글을 쓰고 있는 저는 왜그러는지 잘 모릅니다; 전 protocol buffers를 개발한 사람이 아니고, 어떻게 구현되었는지 파고 싶지도 않거든요..(파고들어도 모르겠지만 ㅠㅠ)


단지 제가 하고 싶은 얘기는 위와 같은 현상이 일어 날 수 있으니까 특히 값이 0일 경우 길이가 0인 배열이 발생하니까 사용하실때 주의 하라는 점을 말씀드리고 싶었습니다.


잇힝~


그럼 세번째 포스트를 기대하세요~ (아마 세번째 포스트가 올라오지 못하면 이 마지막 라인은 사라질겁니다. 헷;

'In to the C#' 카테고리의 다른 글

Delegates와 Serialization  (0) 2014.01.17
Dispose in C#  (0) 2014.01.14
Thread Pool과 Task  (0) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 세번째  (0) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 첫번째  (0) 2014.01.13
In to the C# 2014. 1. 13. 18:36

Google Protocol Buffer 사용해보기 with C# - 첫번째

아래 DeathKnight 님께서 추신을 다신 관계로 Protobuf-net에 대해 올리겠습니다.


Protobuf-net.


이름에서도 풍기듯이 .NET 프레임워크에서 사용가능하며, 버전별 빌드를 제공하고 있습니다.

https://code.google.com/p/protobuf-net/


위의 사이트에서 다운을 받을 수도 있고, VisualStudio NuGet에서도 다운로드 받을 수 있습니다.

솔루션 탐색기에서 참조에 protobuf-net을 추가하고, using ProtoBuf를 추가 합니다.


사용방법은 아래와 같습니다.


Line 8 ~ 19까지는 Packet 클래스입니다. [ProtoContract]는 이 클래스는 ProtoBuf-net 직렬화 대상 클래스를 알리는 Attibute 입니다. [Protomember]는 ProtoBuf-net 직렬화 대상 멤버임을 알려주며, 숫자는 Order Number입니다.


Line 21 ~ 32는 Packet 클래스의 세번째 멤버인 리스트에 사용되는 클래스 입니다. 


Line 38 ~ 45에서 테스트용으로 Packet 인스턴스를 채워 주웠구요.


Line 52 ~ 56은 byte 배열로 직렬화 하였습니다. 인스턴스를 MemoryStream 인스턴스에 담은 후 메모리 스트림에서 byte 배열로 변환 합니다.


Line 59 ~ 60은 byte 배열에서 인스턴스로 역직렬화 하였습니다. 그리고 출력하는 내용입니다. 출력 결과는 아래와 같습니다.



타 언어와는 다르게 .proto 파일을 만들 필요가 없으며, generator를 사용할 필요도 없습니다.

우왕 ㅋ굳ㅋ


두번째 ProtoBuf-net 이야기를 기대하세요~ (대단한건 없겠지만요;;;;)

'In to the C#' 카테고리의 다른 글

Delegates와 Serialization  (0) 2014.01.17
Dispose in C#  (0) 2014.01.14
Thread Pool과 Task  (0) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 세번째  (0) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 두번째  (1) 2014.01.14
hello world 2014. 1. 13. 17:16

Google Protocol Buffer 사용해보기

참고 : https://developers.google.com/protocol-buffers/?hl=ko


구조화된 데이터의 직렬화( Serializing )를 도와줌


  • 장점 : 익숙한 포멧으로 사용하기 편하고, 다양한 플랫폼을 지원함
  • 단점 : cpp 의 경우 proto 파일이 변경되면 컴파일 해야하고, 그로인한 .h파일의 변경으로 전체 빌드가 될 가능성이 높음

프로토콜의 정의 ( .proto 파일 )

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
}


Cpp 에서 사용 - 쓰기 


proto 에서 정의한 내용을 class 로 사용할 수 있고, 각 멤버 함수를 사용할 수 있다

멤버함수는 알아서 찾아보시고...

Person person;
person.set_name(“John Doe”);
person.set_id(1234);
person.set_email(“123@redduck.com”)
fstream input(“myfile”, ios::in | ios::binary);
person.SirializeToOstream( );

Cpp 에서 사용 - 읽기 


네트워크에서 읽어온 버퍼를 읽던지, 파일에서 읽던지, outstream 에서 읽던지... 

읽으면 클래스에 값이 채워짐

fstream input(“mysql”, ios::in | ios::binary );
Person person;
person.ParseFromIstream(&input)
cout << “Name: “ << person.name() << endl 
     << “Email : “ << person.email() << endl;


Memory DB 와 사용 예 : 

  1. 프로토 버퍼의 SerializeToString 함수를 사용하여 보내는 패킷자체의 String 을 Key-value DB ( 난 couchbase 사용 ) 에 저장 
    1. key='user_id:record' value='......' 이딴식
  2. 다른 유저의 전적을 확인할때, memory-db에 없으면 oracle 에서 찾아서 데이터를 가공한후 memory-db에 저장
  3. 다른 유저 or 같은 데이터를 요청 할때 memory-db 에서 찾아서 클라이언트에 보내줌
  4. memory-db 에 data를 변경할 필요가 있는 경우 그냥 지워버림 ( 그럼 다시 2번 과정 )
tip : 
  • int (int32, uint32, int64, uin64)의 필드를 repeated 로 선언하는 경우 뒤에 [ packed=true ] 옵션을 를 사용하면 패킷이 더 컴팩트 해진다고 합니다. 무조건 붙이세욧

ps : C#에서는 더럽게 편하다고 상욱이가 그랬음