Protocol Buffer 기술 깊이 이해(C+인 스 턴 스)

11471 단어 protocolbuffer
이 블 로 그 는 여전히 구 글 의 공식 문 서 를 중심 으로 하고 있 으 며,코드 인 스 턴 스 는 우리 가 개발 하고 있 는 데모 프로젝트 에서 완전히 추출 되 었 으 며,이전의 시 도 를 통 해 이러한 결합 방식 이 교육 과 내부 의 기술 교류 에 비교적 유리 하 다 고 느 꼈 다.아니면 그 말,가장 좋 은 것 은 없고,가장 적합 한 것 만 있다.블 로 그 를 쓰 고 싶 은 것 도 이 렇 죠.서로 다른 기술 주 제 는 서로 다른 스타일 을 사용 해 야 할 수도 있 습 니 다.자,우리 가능 한 한 빨리 주제 에 들 어가 자.1.대상 언어 코드 생 성 아래 명령 은 MyMessage.proto 파일 에서 정의 하 는 Protocol Buffer 형식의 메 시 지 를 대상 언어(C++)의 코드 로 컴 파일 하 는 데 도움 을 줍 니 다.메시지 의 내용 에 대해 서 는 뒤쪽 에 세그먼트 형식 으로 하나씩 열거 하 는 동시에 첨부 파일 에 모든 소스 코드 를 제공 합 니 다.
 
protoc -I=./message --cpp_out=./src ./MyMessage.proto
위의 명령 행 인자 에서 알 수 있 듯 이 컴 파일 할 파일 은 MyMessage.proto 이 고 그 는 현재 디 렉 터 리 의 message 하위 디 렉 터 리 에 저 장 됩 니 다.-cpp_out 매개 변 수 는 컴 파일 도 구 를 표시 합 니 다.대상 언어 는 C++이 고 출력 디 렉 터 리 는 현재 디 렉 터 리 의 src 하위 디 렉 터 리 입 니 다.이 예 에서 생 성 된 대상 코드 파일 이름 은 MyMessage.pb.h 와 MyMessage.pb.cc 입 니 다.2.간단 한 message 로 생 성 된 C+코드 는 가장 간단 한 message 를 정의 합 니 다.그 중에서 원본 형식의 필드 만 포함 합 니 다.
 
option optimize_for = LITE_RUNTIME;
message LogonReqMessage {
required int64 acctID = 1;
required string passwd = 2;
}
MyMessage 파일 에서 옵션 optimize 를 정의 하기 때문에for 의 값 은 LITERUNTIME,따라서 이.proto 파일 로 생 성 된 모든 C++클래스 의 부모 클래스 는:google::protobuf::Message Lite 입 니 다.:google::protobuf::Message 가 아 닙 니 다.지난 블 로그 에 서 는 Message Lite 류 는 Message 의 부모 클래스 로 Message Lite 에 서 는 Protocol Buffer 가 반사 에 대한 지원 이 부족 하고 이러한 기능 은 모두 Message 류 에서 구체 적 인 실현 을 제공 합 니 다.저희 프로젝트 의 경우 전체 시스템 이 상대 적 으로 폐쇄 적 이 고 더 많은 외부 프로그램 과 상호작용 을 하지 않 습 니 다.이 동시에 저희 클 라 이언 트 부분 은 Android 플랫폼 에서 실 행 됩 니 다.이 를 감안 하여 저 희 는 LITE 버 전의 Protocol Buffer 를 사용 하 는 것 을 고려 합 니 다.이렇게 하면 더욱 높 은 인 코딩 효율 을 얻 을 수 있 을 뿐만 아니 라 코드 컴 파일 을 생 성 한 후에 사용 하 는 자원 도 더욱 적 고 반사 가 가 져 올 수 있 는 유연성 과 확장 성 은 이 프로젝트 에 있어 무시 할 수 있다.message LogonReqMessage 에서 생 성 된 C++클래스 의 일부 설명 과 자주 사용 하 는 방법 에 대한 설명 을 살 펴 보 겠 습 니 다.
 
class LogonReqMessage : public ::google::protobuf::MessageLite {
public:
LogonReqMessage();
virtual ~LogonReqMessage();
// implements Message ----------------------------------------------
// MessageLite 。
// LogonReqMessage , clone。
LogonReqMessage* New() const;
// LogonReqMessage , (operator=)
void CopyFrom(const LogonReqMessage& from);
// , 。
void Clear();
// 。
bool IsInitialized() const;
// , 。
int ByteSize() const;
// 。
::std::string GetTypeName() const;
// required int64 acctID = 1;
// message acctID 。
// AcctID 。 k + FieldName( ) + FieldNumber。
static const int kAcctIDFieldNumber = 1;
// acctID true, false。
inline bool has_acctid() const;
// has_acctid false, acctid acctID 。
inline void clear_acctid();
// acctid , int64 。
inline ::google::protobuf::int64 acctid() const;
// acctid , has_acctid true。
inline void set_acctid(::google::protobuf::int64 value);
// required string passwd = 2;
// message passwd 。 acctid
// 。 。
static const int kPasswdFieldNumber = 2;
inline bool has_passwd() const;
inline void clear_passwd();
inline const ::std::string& passwd() const;
inline void set_passwd(const ::std::string& value);
// const char* 。
inline void set_passwd(const char* value);
inline void set_passwd(const char* value, size_t size);
// passwd 。 has_passwd true。
inline ::std::string* mutable_passwd();
// passwd , passwd 。 ,passwd
// 。 has_passwd false。
inline ::std::string* release_passwd();
private:
... ...
};
다음은 LogonReqMessage 대상 의 C++테스트 코드 와 설명 설명 을 읽 습 니 다.
 
void testSimpleMessage()
{
printf("==================This is simple message.================
");
// LogonReqMessage 。
LogonReqMessage logonReq;
logonReq.set_acctid(20);
logonReq.set_passwd("Hello World");
// ,
// 。 , 。
// , 。
int length = logonReq.ByteSize();
char* buf = new char[length];
logonReq.SerializeToArray(buf,length);
// LogonReqMessage , 。
LogonReqMessage logonReq2;
logonReq2.ParseFromArray(buf,length);
printf("acctID = %I64d, password = %s
",logonReq2.acctid(),logonReq2.passwd().c_str());
delete [] buf;
}
3.포 함 된 message 로 생 성 된 C+코드 enum UserStatus{OFFLINE=0;ONLINE = 1; } enum LoginResult { LOGON_RESULT_SUCCESS = 0; LOGON_RESULT_NOTEXIST = 1; LOGON_RESULT_ERROR_PASSWD = 2; LOGON_RESULT_ALREADY_LOGON = 3; LOGON_RESULT_SERVER_ERROR = 4; } message UserInfo { required int64 acctID = 1; required string name = 2; required UserStatus status = 3; } message LogonRespMessage { required LoginResult logonResult = 1; required UserInfo userInfo = 2; //여기에 User Info 메시지 가 포함 되 어 있 습 니 다.}상기 메시지 가 생 성 된 C++코드 에 대해 User Info 는 원본 필드 만 포함 되 어 있 기 때문에 상기 LogonReqMessage 와 큰 차이 가 없습니다.여기 도 중복 되 지 않 습 니 다.LogonRespMessage 메시지 에 User Info 형식의 필드 가 포함 되 어 있 기 때문에 이 메시지 가 생 성 된 C++코드 와 관건 적 인 설명 만 보 여 줍 니 다.
 
class LogonRespMessage : public ::google::protobuf::MessageLite {
public:
LogonRespMessage();
virtual ~LogonRespMessage();
// implements Message ----------------------------------------------
... ... // 。
// required .LoginResult logonResult = 1;
// message logonResult 。
// , LoginResult。
static const int kLogonResultFieldNumber = 1;
inline bool has_logonresult() const;
inline void clear_logonresult();
inline LoginResult logonresult() const;
inline void set_logonresult(LoginResult value);
// required .UserInfo userInfo = 2;
// message UserInfo 。
// 。
static const int kUserInfoFieldNumber = 2;
inline bool has_userinfo() const;
inline void clear_userinfo();
inline const ::UserInfo& userinfo() const;
// userInfo set_userinfo ,
// mutable_userinfo 。 ,Protocol Buffer
// , has_userinfo true。 ,
// userInfo , userInfo 。
inline ::UserInfo* mutable_userinfo();
inline ::UserInfo* release_userinfo();
private:
... ...
};
다음은 LogonRespMessage 대상 의 C++테스트 코드 와 설명 설명 설명 을 읽 습 니 다.
 
void testNestedMessage()
{
printf("==================This is nested message.================
");
LogonRespMessage logonResp;
logonResp.set_logonresult(LOGON_RESULT_SUCCESS);
// , mutable_userinfo userInfo , 。
UserInfo* userInfo = logonResp.mutable_userinfo();
userInfo->set_acctid(200);
userInfo->set_name("Tester");
userInfo->set_status(OFFLINE);
int length = logonResp.ByteSize();
char* buf = new char[length];
logonResp.SerializeToArray(buf,length);
LogonRespMessage logonResp2;
logonResp2.ParseFromArray(buf,length);
printf("LogonResult = %d, UserInfo->acctID = %I64d, UserInfo->name = %s, UserInfo->status = %d
"
,logonResp2.logonresult(),logonResp2.userinfo().acctid(),logonResp2.userinfo().name().c_str(),logonResp2.userinfo().status());
delete [] buf;
}
4.repeated 내장 message 가 생 성 한 C+코드 message Buddy Info{required UserInfo userInfo=1;required int32 groupID = 2; } message RetrieveBuddiesResp { required int32 buddiesCnt = 1; repeated BuddyInfo buddiesInfo = 2; } 상기 메시지 가 생 성 된 코드 에 대해 저 희 는 Retrievedies Resp 메시지 에 대응 하 는 C+코드 에 대해 상세 하 게 설명 할 것 입 니 다.나머지 부분 은 앞의 소절 의 예 와 대체적으로 같 고 직접 참조 할 수 있 습 니 다.그리고 RetrievediesResp 류 의 코드 에 대해 서도 저 희 는 buddiesInfo 필드 에서 생 성 된 코드 에 대해 더욱 상세 하 게 설명 할 뿐 입 니 다.
 
class RetrieveBuddiesResp : public ::google::protobuf::MessageLite {
public:
RetrieveBuddiesResp();
virtual ~RetrieveBuddiesResp();
... ... // 。
// repeated .BuddyInfo buddiesInfo = 2;
static const int kBuddiesInfoFieldNumber = 2;
// 。
inline int buddiesinfo_size() const;
// , ,buddiesinfo_size 0。
inline void clear_buddiesinfo();
// 。
inline const ::BuddyInfo& buddiesinfo(int index) const;
// , 。
inline ::BuddyInfo* mutable_buddiesinfo(int index);
// 。 , 。
inline ::BuddyInfo* add_buddiesinfo();
// buddiesInfo , , 。
inline const ::google::protobuf::RepeatedPtrField< ::BuddyInfo >&
buddiesinfo() const;
// buddiesInfo , 。
inline ::google::protobuf::RepeatedPtrField< ::BuddyInfo >*
mutable_buddiesinfo();
private:
... ...
};
다음은 RetrieveBuddies Resp 대상 의 C++테스트 코드 와 설명 설명 설명 을 읽 습 니 다.
 
void testRepeatedMessage()
{
printf("==================This is repeated message.================
");
RetrieveBuddiesResp retrieveResp;
retrieveResp.set_buddiescnt(2);
BuddyInfo* buddyInfo = retrieveResp.add_buddiesinfo();
buddyInfo->set_groupid(20);
UserInfo* userInfo = buddyInfo->mutable_userinfo();
userInfo->set_acctid(200);
userInfo->set_name("user1");
userInfo->set_status(OFFLINE);
buddyInfo = retrieveResp.add_buddiesinfo();
buddyInfo->set_groupid(21);
userInfo = buddyInfo->mutable_userinfo();
userInfo->set_acctid(201);
userInfo->set_name("user2");
userInfo->set_status(ONLINE);
int length = retrieveResp.ByteSize();
char* buf = new char[length];
retrieveResp.SerializeToArray(buf,length);
RetrieveBuddiesResp retrieveResp2;
retrieveResp2.ParseFromArray(buf,length);
printf("BuddiesCount = %d
",retrieveResp2.buddiescnt());
printf("Repeated Size = %d
",retrieveResp2.buddiesinfo_size());
// 。
// , buddiesinfo_size buddiesinfo 。
RepeatedPtrField<BuddyInfo>* buddiesInfo = retrieveResp2.mutable_buddiesinfo();
RepeatedPtrField<BuddyInfo>::iterator it = buddiesInfo->begin();
for (; it != buddiesInfo->end(); ++it) {
printf("BuddyInfo->groupID = %d
", it->groupid());
printf("UserInfo->acctID = %I64d, UserInfo->name = %s, UserInfo->status = %d
"
, it->userinfo().acctid(), it->userinfo().name().c_str(),it->userinfo().status());
}
delete [] buf;
}
마지막 으로 설명 해 야 할 것 은 Protocol Buffer 는 아직도 매우 유용 한 기능 을 많이 제공 했다 는 것 이다.특히 직렬 화 된 목적지,예 를 들 어 파일 흐름 과 네트워크 흐름 등 이다.이 동시에 완전한 공식 문서 와 규범 적 인 명명 규칙 도 제공 하여 많은 상황 에서 함수 의 이름 을 통 해 함수 가 완성 한 작업 을 직접 알 수 있 습 니 다.이 블 로그 에 사 용 된 예제 코드 를 첨부 파일 로 업로드 하려 고 했 으 나 이 기능 이 발견 되 지 않 았 음 을 양해 바 랍 니 다.

좋은 웹페이지 즐겨찾기