protobuf转json
方法介绍
protobuf的介绍在这里就不详细介绍了,主要是俺也是刚接触,感兴趣的同学可以去搜索相关博客或者直接去看源码以及google的官方文档(官方文档表示很吃力)或者去这个网站:https://developers.google.com/protocol-buffers/docs/overview查看相应内容,这里面内容很全面,可以很方面的查询各个函数的使用方法以及功能。本篇文章主要介绍一下本人最近做的一个protobuf转json的小工具,下面进行拆分讲解,完整的代码在:git@github.com:chengfeiGitHub/P-bToJson.git。
protobuf自带一个MessageToJson()的函数可以将对应的消息转换成json,一般情况下该函数可以满足转换需求。但是,最近项目的要求使用MessageToJson()无法实现,主要要求是:
- 选择特定的messge进行转换(主要是提供包含需求字段号的set或者vector,根据提供的字段号进行转换);
- 对于Enum类型的消息,可以选择显示枚举名或者枚举值;
- 对于字段值为0的字段,可以选择显示或者不显示.
主要有这三个要求,对于功能2、3现在最新的protobuf应该是支持的,但是没有功能1的实现方式,所以只好自己写一个小工具。
说明:本工具由C++编写完成
首先是函数的声明:
#pragma once
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h> void ChooseSomeFieldsToJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, std::vector<uint>& needs, bool Enum_2_Str, bool Showzero);
//Enum_2_Str: ture显示枚举名,false:显示枚举值; Showzero: ture显示值为0的fields,false,不显示值为0的fields。
void GetRepeatedJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, const google::protobuf::FieldDescriptor *field, const ::google::protobuf::Reflection *reflection, bool Enum_2_Str,bool Showzero);
void NeedEmptyToJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, bool Enum_2_Str, bool Showzero);
void NeedNotEmptyToJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, std::vector<uint>& needs, bool Enum_2_Str, bool Showzero);
int AppendTmpString1(std::string& pb2jsonstring,std::string& tmp_string, int judge);
int AppendTmpString2(std::string& pb2jsonstring,std::string& tmp_string, int judge);
pb2jsonstring是存储转换结果的字符串,msg是需要转换的消息,needs是需要转换的字段号;函数GetRepeatedJson()是对重复的字段进行操作;NeedEmptyToJson()是当needs为空时对应的操作(needs为空表示需要转换所有的字段);NeedNotEmptyToJson()是当needs不为空时对应的操作;AppendTmpStrign1()以及AppendTmpStrign2()是将临时字符串添加到pb2jsonstring后的操作。
上面的代码保存到一个头文件当中,就叫pbjsontest3.h吧,然后是pbjsontest3.cpp
#include <iostream>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <set>
#include <string>
#include "pbjsontest3.h" using namespace ::google::protobuf; void ChooseSomeFieldsToJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, std::vector<uint>& need, bool Enum_2_Str, bool Showzero)
{ const Descriptor* descriptor = msg.GetDescriptor();
const Reflection* reflection = msg.GetReflection();
if (need.empty()) //如果needs为空,表示需要将所有的字段转换为json
{
NeedEmptyToJson(pb2jsonstring, msg, Enum_2_Str, Showzero);
}
else
{
NeedNotEmptyToJson(pb2jsonstring, msg, need, Enum_2_Str, Showzero);
}
}
这一部分主要就是判断need是否为空,然后选择相应的函数进行操作,不在做详细的叙述,下面是NeedEmptyToJson()的介绍。由于这一部分代码太长,所以相应的介绍在代码中进行注释说明。
void NeedEmptyToJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, bool Enum_2_Str, bool Showzero)
{
const Descriptor* descriptor = msg.GetDescriptor();
const Reflection* reflection = msg.GetReflection();
const uint count = descriptor->field_count(); //count为当前消息中所有的字段总数
uint judge = ;//judge用来判断是否在当前json元素前加“,”用来分隔前后元素,如果judge==0,则不加,如果jugdge==1,则加“,”
std::string tmp_string; //临时变量
std::int32_t v32=;
std::uint32_t vu32=;
std::int64_t v64=;
std::uint64_t vu64=;
double vd=;
std::string str;
pb2jsonstring.append("{"); //添加第一个"{"
for (int it = ; it <count; ++it)
{
const FieldDescriptor* goal_field=descriptor->field(it);
/*这里要用field()来取字段,因为field()是按字段的实际标号来取字段,而不是根据字段号来进行取字段,这样就避免的字段号不连续造成的某些字段取不到的问题。 */
if(nullptr==goal_field) //不存在字段
{
continue;
} if (goal_field->is_repeated()) //判断字段是否为repeated
{
if (reflection->FieldSize(msg, goal_field) > )
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string .append("["); //重复的字段用[]包围
GetRepeatedJson(tmp_string, msg, goal_field, reflection, Enum_2_Str,Showzero);
tmp_string.append("]");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
continue;
}
switch (goal_field->type())
{
case FieldDescriptor::TYPE_MESSAGE:
{
const Message& tmp_msg = reflection->GetMessage(msg, goal_field);
if ( != tmp_msg.ByteSize())
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
NeedEmptyToJson(tmp_string,tmp_msg, Enum_2_Str, Showzero);
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break; case FieldDescriptor::TYPE_INT32:
{
v32=reflection->GetInt32(msg, goal_field);
if(v32==)
{
if(Showzero) //字段值为0,也需要进行打印
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v32)); //需要抓换成字符型
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break; case FieldDescriptor::TYPE_UINT32:
{
vu32=reflection->GetUInt32(msg, goal_field);
if(vu32==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break; case FieldDescriptor::TYPE_INT64:
{
v64=reflection->GetInt64(msg, goal_field);
if(v64==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_UINT64:
{
vu64=reflection->GetUInt64(msg, goal_field);
if(vu64==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
{ str=reflection->GetString(msg, goal_field);
if(str.empty())
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append("\"").append(str).append("\"");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append("\"").append(str).append("\"");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge); }
}
break;
case FieldDescriptor::TYPE_DOUBLE:
{
vd=reflection->GetDouble(msg, goal_field);
if(vd==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vd));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vd));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_BOOL:
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
if (reflection->GetBool(msg, goal_field))
tmp_string.append("true");
else
tmp_string.append("false");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge); }
break;
case FieldDescriptor::TYPE_ENUM:
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
if (Enum_2_Str) //判断显示枚举名还是枚举值
{
tmp_string.append("\"").append(reflection->GetEnum(msg,goal_field)->name()).append("\"");
}
else
{
static char enumstr[];
memset(enumstr, , sizeof(enumstr));
snprintf(enumstr, sizeof(enumstr), "%d", reflection->GetEnum(msg,goal_field)->number());
tmp_string.append(enumstr);
}
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
break;
default:
break;
}
}
pb2jsonstring.append("}");
} int AppendTmpString1(std::string &pb2jsonstring,std::string &tmp_string, int judge)
{
if ( judge!= && tmp_string.length()!=)
{
pb2jsonstring.append(",").append(tmp_string);
return judge;
}
else if(judge== && tmp_string.length()!=)
{
pb2jsonstring.append(tmp_string);
return ;
}
return judge;
}
下面need不为空时候的转换:
void NeedNotEmptyToJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, std::vector<uint>& needs, bool Enum_2_Str, bool Showzero)
{
const Descriptor* descriptor = msg.GetDescriptor();
const Reflection* reflection = msg.GetReflection(); uint judge = ;
std::string tmp_string;
std::int32_t v32=;
std::uint32_t vu32=;
std::int64_t v64=;
std::uint64_t vu64=;
double vd=;
std::string str; pb2jsonstring.append("{"); for (auto it=needs.begin(); it != needs.end(); ++it)
{
const FieldDescriptor* goal_field=descriptor->FindFieldByNumber(*it);
//need为空的转换和不为空的几乎一样,主要差别是对字段的提取,不为空时需要使用FindFieldByNumber()来进行操作,这样可以取任意字段号对应的字段。将need为空和不为空分开写主要是测试中这样可以节省时间,其实是可以写到一块的,有兴趣的同学可以进行修改。 if(nullptr==goal_field) //不存在字段
{
continue;
} if (goal_field->is_repeated())
{
if (reflection->FieldSize(msg, goal_field) > )
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string .append("[");
GetRepeatedJson(tmp_string, msg, goal_field, reflection, Enum_2_Str,Showzero);
tmp_string.append("]");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
continue;
}
switch (goal_field->type())
{
case FieldDescriptor::TYPE_MESSAGE:
{
const Message& tmp_msg = reflection->GetMessage(msg, goal_field);
if ( != tmp_msg.ByteSize())
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
NeedEmptyToJson(tmp_string,tmp_msg, Enum_2_Str, Showzero);
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break; case FieldDescriptor::TYPE_INT32:
{
v32=reflection->GetInt32(msg, goal_field);
if(v32==)
{
if(Showzero) //字段值为0,也需要进行打印
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break; case FieldDescriptor::TYPE_UINT32:
{
vu32=reflection->GetUInt32(msg, goal_field);
if(vu32==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break; case FieldDescriptor::TYPE_INT64:
{
v64=reflection->GetInt64(msg, goal_field);
if(v64==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(v64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_UINT64:
{
vu64=reflection->GetUInt64(msg, goal_field);
if(vu64==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vu64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
{ str=reflection->GetString(msg, goal_field);
if(str.empty())
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append("\"").append(str).append("\"");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append("\"").append(str).append("\"");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge); }
}
break;
case FieldDescriptor::TYPE_DOUBLE:
{
vd=reflection->GetDouble(msg, goal_field);
if(vd==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vd));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
tmp_string.append(std::to_string(vd));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_BOOL:
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
if (reflection->GetBool(msg, goal_field))
tmp_string.append("true");
else
tmp_string.append("false");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge); }
break;
case FieldDescriptor::TYPE_ENUM:
{
tmp_string="";
tmp_string.append("\"").append(goal_field->name()).append("\":");
if (Enum_2_Str)
{
tmp_string.append("\"").append(reflection->GetEnum(msg,goal_field)->name()).append("\"");
}
else
{
static char enumstr[];
memset(enumstr, , sizeof(enumstr));
snprintf(enumstr, sizeof(enumstr), "%d", reflection->GetEnum(msg,goal_field)->number());
tmp_string.append(enumstr);
}
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
break;
default:
break;
}
}
pb2jsonstring.append("}");
}
然后就是需要对repeated的字段进行相应的转换,
void GetRepeatedJson(std::string& pb2jsonstring, const ::google::protobuf::Message& msg, const google::protobuf::FieldDescriptor *goal_field, const ::google::protobuf::Reflection *reflection, bool Enum_2_Str,bool Showzero)
{
std::string tmp_string;
int judge=;
std::int32_t v32=;
std::uint32_t vu32=;
std::int64_t v64=;
std::uint64_t vu64=;
double vd=;
std::string str;
for (int i = ; i < reflection->FieldSize(msg, goal_field); ++i)
{
switch (goal_field->type())
{
case FieldDescriptor::TYPE_MESSAGE:
{
const Message& tmp_msg = reflection->GetRepeatedMessage(msg, goal_field, i);
if ( != tmp_msg.ByteSize())
{
tmp_string="";
//当重复的是message时,需要全部进行转换,不需要选择特定的字段进行转换,当然有这个需求的也可以进行相应的改进,不过会麻烦一些。重复字段的提取主要就是Get方式的不同,这个可以查阅文章开头中提到的文档,里面有详细说明
NeedEmptyToJson(tmp_string, tmp_msg, Enum_2_Str,Showzero);
judge = AppendTmpString2(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_INT32:
{
v32=reflection->GetRepeatedInt32(msg, goal_field,i);
if(v32==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append(std::to_string(v32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append(std::to_string(v32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
} break;
case FieldDescriptor::TYPE_UINT32:
{
vu32=reflection->GetRepeatedUInt32(msg, goal_field,i);
if(vu32==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append(std::to_string(vu32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append(std::to_string(vu32));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_INT64:
{
v64=reflection->GetRepeatedInt64(msg, goal_field,i);
if(v64==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append(std::to_string(v64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append(std::to_string(v64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
break;
case FieldDescriptor::TYPE_UINT64:
{
vu64=reflection->GetRepeatedUInt64(msg, goal_field,i);
if(vu64==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append(std::to_string(vu64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append(std::to_string(vu64));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
} }
break;
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
{
str="";
str=reflection->GetRepeatedString(msg, goal_field,i);
if(str.empty())
{
if(Showzero)
{
tmp_string="";
tmp_string.append("\"").append(str).append("\"");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append("\"").append(str).append("\"");
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge); }
}
break;
case FieldDescriptor::TYPE_DOUBLE:
{
vd=reflection->GetRepeatedDouble(msg, goal_field,i);
if(vd==)
{
if(Showzero)
{
tmp_string="";
tmp_string.append(std::to_string(vd));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
}
}
else
{
tmp_string="";
tmp_string.append(std::to_string(vd));
judge = AppendTmpString1(pb2jsonstring,tmp_string,judge);
} }
break;
case FieldDescriptor::TYPE_BOOL:
{
tmp_string="";
if(reflection->GetRepeatedBool(msg, goal_field,i))
tmp_string.append("true");
else
tmp_string.append("false");
judge = AppendTmpString2(pb2jsonstring,tmp_string,judge); }
break;
case FieldDescriptor::TYPE_ENUM:
{
tmp_string="";
if (Enum_2_Str)
{
tmp_string.append("\"").append(reflection->GetRepeatedEnum(msg,goal_field,i)->name()).append("\"");
}
else
{
static char enumstr[];
memset(enumstr, , sizeof(enumstr));
snprintf(enumstr, sizeof(enumstr), "%d", reflection->GetRepeatedEnum(msg,goal_field,i)->number());
tmp_string.append(enumstr);
}
judge = AppendTmpString2(pb2jsonstring,tmp_string,judge);
}
break;
default:
break;
}
}
}
int AppendTmpString2(std::string &pb2jsonstring,std::string &tmp_string, int judge)
{
if( judge!= && tmp_string.length()!=)
{
pb2jsonstring.append(",").append(tmp_string);
return judge;
}
else if( judge== && tmp_string.length()!=)
{
pb2jsonstring.append(tmp_string);
return ;
}
return judge;
}
总结说明
本文中介绍的方法从逻辑上来说没有什么特别的地方,就是读取字段名,字段值然后添加到对应的字符串当中,代码比较繁琐,还有很大的改进空间,后来使用宏定义的##操作减少了很多代码量,比如GetInt()与GetRepeatedInt()可以通过使用“##”操作合并到一个函数中进行操作。
文中有不合理的地方希望各位批评指正。
protobuf转json的更多相关文章
- protobuf与json互相转换
Java http://code.google.com/p/protobuf-java-format/ maven <dependency> <groupId>com.goog ...
- protobuf与json相互转换的方法
google的protobuf对象转json,不能直接使用FastJson之类的工具进行转换,原因是protobuf生成对象的get方法,返回的类型有byte[],而只有String类型可以作为jso ...
- protobuf与json转换
protobuf对象不能直接使用jsonlib去转,因为protobuf生成的对象的get方法返回的类型有byte[],而只有String类型可以作为json的key,protobuf提供方法进行转换 ...
- protobuf json xml比较
1 protobuf/xml/json对比 从数据的存储格式的角度进行对比 假如要存储一个键值对: {price:150} 1.1 protobuf的表示方式 message Test { opti ...
- Protobuf有没有比JSON快5倍?用代码来击破pb性能神话
转 http://www.sohu.com/a/136487507_505779 2017-04-26 07:58 程序设计 /58 /技术 导读:Google 的 Protocol Buffers ...
- Protobuf的简单介绍、使用和分析
Protobuf的简单介绍.使用和分析 一.protobuf是什么? protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库( ...
- 通讯协议序列化解读(一) Protobuf详解教程
前言:说到JSON可能大家很熟悉,是目前应用最广泛的一种序列化格式,它使用起来简单方便,而且拥有超高的可读性.但是在越来越多的应用场景里,JSON冗长的缺点导致它并不是一种最优的选择. 一.常用序列化 ...
- Android Protobuf应用及原理
前言 之前一直忙于移动端日志SDK Trojan的开源工作,已十分稳定地运行在饿了么团队App中,集成了日志加密和解密功能.哎呀,允许我卖个狗皮膏药,不用不知道,用了就知道,从此爱不释手,Trojan ...
- Swoole http server + yaf, swoole socket server + protobuf 等小结
拥抱swoole, 拥抱更好的php Swoole 是什么? Yaf 是什么? 接触swoole已经4年多了,一直没有好好静下心来学习.一直在做web端的应用,对网络协议和常驻内存型服务器一窍不通.一 ...
随机推荐
- 数组去重,call、apply、bind之间的区别,this用法总结
一.数组去重,直接写到Array原型链上. //该方法只能去除相同的数字 不会去判断24和'24'是不同的 所有数字和字符串数字是相同是重复的 Array.prototype.redup=functi ...
- .Net程序员学用Oracle系列(30):零碎补充、最后总结(The End)
1.同义词 2.Flashback 技术 3.连接字符串的写法 4.转义字符 & 特殊运算符 5.文件类型 6.查看参数 & 修改参数 7.AWR 工具 8.学习方法 & 学习 ...
- 开涛spring3(6.1) - AOP 之 6.1 AOP基础
6.1.1 AOP是什么 考虑这样一个问题:需要对系统中的某些业务做日志记录,比如支付系统中的支付业务需要记录支付相关日志,对于支付系统可能相当复杂,比如可能有自己的支付系统,也可能引入第三方支付平 ...
- 动手写个数字输入框1:input[type=number]的遗憾
前言 最近在用Polymer封装纯数字的输入框,开发过程中发现不少坑,也有很多值得研究的地方.本系列打算分4篇来叙述这段可歌可泣的踩坑经历: <动手写个数字输入框1:input[type=nu ...
- WebLogic 安装
首先 需要下载好Weblogic 官网:http://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-main-097127. ...
- ArcGIS 网络分析[2.5] VRP(车辆配送)
什么是VRP? VRP就是车辆配送. 大家有没有想象过一个城市的某个快递营业点,是怎么让各个快递员配送快递的? 每个快递员针对那片区域的客户,如何走路线才最省时间? 也许你会说,最短路径分析可以做到— ...
- DDD理论学习系列(4)-- 领域模型
DDD理论学习系列目录 1.引言 我们还是先来拆词理解,领域模型可以拆为"领域"和"模型"二词. 领域:按照我们之前的文章的理解,DDD中的领域是指软件系统要解 ...
- SDN学习之实现环路通信
在对OpenFlow协议有了一定了解以后,开始尝试如何通过Ryu控制器实现网络中的通信.根据协议,我们知道,当数据信息首次传输到交换机时,由于交换机不存在该数据信息所对应的流表,因此,会触发Packe ...
- 网络编程2之Socket简介和java.net包
一.Socket 通信链路的端点就被称为"套接字"(英文名Socket) 是提供给应用程序的接口 图文说明Socket Socket通信原理 二.java.net包 Java.ne ...
- HTML5之2D物理引擎 Box2D for javascript Games 系列 第三部分之创建图腾破坏者的关卡
创建图腾破坏者的关卡 现在你有能力创建你的第一个游戏原型,我们将从创建图腾破坏者的级别开始. 为了展示我们所做事情的真实性,我们将流行的Flash游戏图腾破坏者的一关作为 我们模仿的对象.请看下面的截 ...