#include <string>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/text_format.h>
#include "simplemessage.pb.h"
using namespace std;
using namespace google;
// 메세지 사이에 끼워넣을 헤더 구조체
struct MessageHeader
{
protobuf::uint32 size;
simple::MessageType type;
};
const int MessageHeaderSize = sizeof(MessageHeader);
class PacketHandler
{
public:
void Handle(const simple::Login& message) const
{
PrintMessage(message);
}
void Handle(const simple::Chat& message) const
{
PrintMessage(message);
}
void Handle(const simple::Move& message) const
{
PrintMessage(message);
}
protected:
// 메세지의 내용을 텍스트 형식으로 출력
void PrintMessage(const protobuf::Message& message) const
{
string textFormatStr;
protobuf::TextFormat::PrintToString(message, &textFormatStr);
printf("%s\n", textFormatStr.c_str());
}
};
// 패킷을 파싱해서 그것을 인자로 적절한 메서드를 호출해줌
void PacketProcess(protobuf::io::CodedInputStream& input_stream, const PacketHandler& handler)
{
MessageHeader messageHeader;
// 헤더를 읽어냄
while( input_stream.ReadRaw(&messageHeader, MessageHeaderSize) )
{
// 직접 억세스 할수 있는 버퍼 포인터와 남은 길이를 알아냄
const void* payload_ptr = NULL;
int remainSize = 0;
input_stream.GetDirectBufferPointer(&payload_ptr, &remainSize); if (remainSize < (signed)messageHeader.size)
break;
// 메세지 본체를 읽어내기 위한 스트림을 생성
protobuf::io::ArrayInputStream payload_array_stream(payload_ptr, messageHeader.size);
protobuf::io::CodedInputStream payload_input_stream(&payload_array_stream);
// 메세지 본체 사이즈 만큼 포인터 전진
input_stream.Skip(messageHeader.size);
// 메세지 종류별로 역직렬화해서 적절한 메서드를 호출해줌
switch(messageHeader.type)
{
case simple::LOGIN:
{
simple::Login message;
if (false == message.ParseFromCodedStream(&payload_input_stream))
break;
handler.Handle(message);
}
break;
case simple::CHAT:
{
simple::Chat message;
if (false == message.ParseFromCodedStream(&payload_input_stream))
break;
handler.Handle(message);
}
break;
case simple::MOVE:
{
simple::Move message;
if (false == message.ParseFromCodedStream(&payload_input_stream))
break;
handler.Handle(message);
}
break;
}
}
}
// 메세지를 출력용 스트림에 쓴다
void WriteMessageToStream(
simple::MessageType msgType,
const protobuf::Message& message,
protobuf::io::CodedOutputStream& stream)
{
MessageHeader messageHeader;
messageHeader.size = message.ByteSize();
messageHeader.type = msgType;
stream.WriteRaw(&messageHeader, sizeof(MessageHeader));
message.SerializeToCodedStream(&stream);
}
int main(int argc, char* argv[])
{
// 메세지에 값 세팅
simple::Login login;
login.set_name("alice");
login.set_id(1);
simple::Chat chat;
chat.set_name("rabbit");
chat.set_dst_id(2);
chat.set_message("How are you doing?");
simple::Move move;
move.set_id(3);
simple::Move::Position* pos0 = move.add_track();
pos0->set_x(10.01f);
pos0->set_y(10.02f);
simple::Move::Position* pos1 = move.add_track();
pos1->set_x(20.01f);
pos1->set_y(20.02f);
simple::Move::Position* pos2 = move.add_track();
pos2->set_x(30.01f);
pos2->set_y(30.02f);
// 필요한 버퍼의 사이즈를 알아내서 버퍼를 할당
int bufSize = 0;
bufSize += MessageHeaderSize + login.ByteSize();
bufSize += MessageHeaderSize + chat.ByteSize();
bufSize += MessageHeaderSize + move.ByteSize();
protobuf::uint8* outputBuf = new protobuf::uint8[bufSize];
// 메세지를 출력할 스트림 생성
protobuf::io::ArrayOutputStream output_array_stream(outputBuf, bufSize);
protobuf::io::CodedOutputStream output_coded_stream(&output_array_stream);
// 메세지를 스트림에 쓴다
WriteMessageToStream(simple::LOGIN, login, output_coded_stream);
WriteMessageToStream(simple::CHAT, chat, output_coded_stream);
WriteMessageToStream(simple::MOVE, move, output_coded_stream);
// 패킷 핸들러와 입력용 스트림 생성
PacketHandler handler;
protobuf::io::ArrayInputStream input_array_stream(outputBuf, bufSize);
protobuf::io::CodedInputStream input_coded_stream(&input_array_stream);
// 패킷 분석
PacketProcess(input_coded_stream, handler);
// 버퍼 해제
delete [] outputBuf;
outputBuf = NULL;
return 0;
}
최근 덧글