分类归档 操作系统

通过admin

Protobuf C++ serialize到char*的方法

protobuf的Demo程序是

C++版本的protubuf有几种serialize和unSerialize的方法:

方法一:

官方demo程序采用的是

// Write the new address book back to disk.

fstream output(argv[1], ios::out | ios::trunc | ios::binary);

if (!address_book.SerializeToOstream(&output)) {

cerr << “Failed to write address book.” << endl;

return -1;

}

 

// Read the existing address book.

fstream input(argv[1], ios::in | ios::binary);

if (!input) {

cout << argv[1] << “: File not found.  Creating a new file.” << endl;

} else if (!address_book.ParseFromIstream(&input)) {

cerr << “Failed to parse address book.” << endl;

return -1;

}

 

 

上面采用的是fstream,把数据序列(反序列)打磁盘文件中。

 

而如果想序列到char *,并且通过socket传输,则可以使用:

方法二:

int size = address_book.ByteSize();

void *buffer = malloc(size);

address_book.SerializeToArray(buffer, size);

 

方法三:

使用ostringstream ,

std::ostringstream stream;

address_book.SerializeToOstream(&stream);

 

string text = stream.str();

char* ctext = string.c_str();

通过admin

详解Google-ProtoBuf中结构化数据的编码

原文:http://www.wuzesheng.com/?p=1258

本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf。因此,本文首先会介绍一些google protobuf相关的内容,让读者朋友对google protobuf有一个初步的印象,然后,再开始进入正题—-深入浅出地介绍google protobuf中用到的编码规则。下面言归正传,开始今天的话题。

1. Google-ProtoBuf是什么

ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf。

ProtoBuf可以支持多种编程语言,目前已经C++, Java和Python,本文中所前的内容用到例子的话,会以C++为例。

2.如何得到Google-ProtoBuf

ProtoBuf在Google Code上的主页是:http://code.google.com/p/protobuf/, 感兴趣的朋友可以在这里下载ProtoBuf的源码,也可以在这里阅读ProtoBuf的详细的文档。

3. 深入浅出Google-ProtoBuf中的编码规则

(1)序列化和反序列化:

在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化。这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不太好理解,在这里我会用比较通俗的文字来解释,尽可能让读都朋友们一读就明白是怎么回事:

序列化:是指将结构化的数据按一定的编码规范转成指定格式的过程

反序列化:是指将转成指定格式的数据解析成原始的结构化数据的过程

举个例子,Person是一个表示人的对象类型,person是一个Person类型的对象,将person存到一个对应的XML文档中的过程就是一种序列化,而解析XML生成对应Person类型对象person的过程,就是一个反序列化的过程。在这里结构化数据指的就是Person类型的数据,一定的编码规范指的就是XML文档的规范。XML是一种简单的序列化方式,用XML序列化的好处是,XML的通用性比较好,另外,XML是一种文本格式,对人阅读比较友好,但是XML方式比较占空间,效率也不是很高。通常,比较高效的序列化都是采用二进制方式的,将要序列化的结构化数据,按一定的编码规范,转成为一串二进制的字节流存储下来,需要用的时候再从这串二进制的字节流中反序列化出对应的结构化的数据。

通过上面的介绍,我们给protobuf下一个比较正式的定义了:Google ProtoBuf是Google制定的一种用来序列化结构化数据的程序库。

(2)ProtoBuf中的编码:

1) ProtoBuf编码基础——Varints, varints是一种将一个整数序列化为一个或者多个Bytes的方法,越小的整数,使用的Bytes越少。

Varints的基本规则是:

(a)每个Byte的最高位(msb)是标志位,如果该位为1,表示该Byte后面还有其它Byte,如果该位为0,表示该Byte是最后一个Byte。

(b)每个Byte的低7位是用来存数值的位

(c)Varints方法用Litte-Endian(小端)字节序

举个例子:300用Varints序列化的结果是1010 1100 0000 0010,运算过程如下所示:

1010 1100 0000 0010->010 1100 000 0010(去标志位)->

000 0010 010 1100(调整字节序)-> 1 0010 1100 ->256+32+8+4=300(计算值)

2)ProtoBuf中消息的编码规则:

(a)每条消息(message)都是有一系列的key-value对组成的, key和value分别采用不同的编码方式。

(b)对某一条件消息(message)进行编码的时候,是把该消息中所有的key-value对序列化成二进制字节流;而解码的时候,解码程序读入二进制的字节流,解析出每一个key-value对,如果解码过程中遇到识别不出来的类型,直接跳过。这样的机制,保证了即使该消息添加了新的字段,也不会影响旧的编/解码程序正常工作。

(c)key由两部分组成,一部分是在定义消息时对字段的编号(field_num),另一部分是字段类型(wire_type)。字段类型定义如下表所示。

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

(d)key的编码方式:field_num << 3 | wire_type

(e)varint类型(wire_type=0)的编码,与第(1)部分中介绍的方法基本一致,但是int32, int64和sint32,sint64有些特别之处:int32和int64就是简单的按varints方法来编码,所以像-1、-2这样负数也会占比较多的Bytes。于是sint32和sint64采用了一种改进的方法:先采用Zigzag方法将所有的整数(正数、0和负数)一一映射到所有的无符号数上,然后再采用varints编码方法进行编码。Zigzag映射函数为:

Zigzag(n) = (n << 1) ^ (n >> 31),  n为sint32时

Zigzag(n) = (n << 1) ^ (n >> 63),  n为sint64时

下表是一个比较直观的映射表,这样映射后再进行编码的好处就是绝对值比较小的负数序列化后的结果占的Bytes数也会比较少。

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2 4
-3 5
2147483647 4294967294
-2147483648 4294967295

(f)64-bit(wire_type=1)和32-bit(wire_type=5)的编码方式就比较简单了,直接在key后面跟上64bits或32bits,采用Little-Endian(小端)字节序。

(g)length-delimited(wire_type=2)的编码方式:key+length+content, key的编码方式是统一的,length采用varints编码方式,content就是由length指定的长度的Bytes。

(h)wire_type=3和4的现在已经不推荐使用了,因此这里也不再做介绍。

3)ProtoBuf编解码中字段顺序(Field order)的问题:

(a) 编码/解码与字段顺序无关,这一点由key-value机制就能保证

(b)对于未知的字段,编码的时候会把它写在序列化完的已知字段后面。

 

源文档 <http://www.wuzesheng.com/?p=1258>

通过admin

Java protobuf框架使用向导

 

ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf。

下面介绍的是使用Java ProtoBuf的基本步骤:

1.http://code.google.com/p/protobuf/downloads/list ,选择其中的win版本下载

2.下载一个protobuf-java-2.4.1.jar文件(注意,要与你刚才下的proto.exe版本相同,否则可能出现编译通不过现象)

http://grepcode.com/snapshot/repo1.maven.org/maven2/com.google.protobuf/protobuf-java/2.4.1

3.在proto.exe同级目录,编写一个msg.proto文件:

 

package tutorial;

 

option java_package = “com.protobuftest.protobuf”;

option java_outer_classname = “PersonProbuf”;

 

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;

 

message CountryInfo {

required string name = 1;

required string code = 2;

optional int32 number = 3;

}

}

 

message AddressBook {

repeated Person person = 1;

}

 

4.使用如下命令编译这个文件:

5.将生成的ProtoBufferPractice.java文件引入eclipse

6.把下载的protobuf-java-2.4.1.jar也引入工程

7.使用方法:

package com.protobuftest;

 

import java.util.List;

 

import com.google.protobuf.InvalidProtocolBufferException;

import com.protobuftest.protobuf.PersonProbuf;

import com.protobuftest.protobuf.PersonProbuf.Person;

import com.protobuftest.protobuf.PersonProbuf.Person.PhoneNumber;

import com.protobuftest.protobuf.PersonProbuf.Person.PhoneNumberOrBuilder;

import com.protobuftest.protobuf.PersonProbuf.Person.PhoneType;

 

public class ProtoBufTest {

 

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

PersonProbuf.Person.Builder builder = PersonProbuf.Person.newBuilder();

builder.setEmail(“kkk@email.com”);

builder.setId(1);

builder.setName(“TestName”);

builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber(“131111111”).setType(PersonProbuf.Person.PhoneType.MOBILE));

builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber(“011111”).setType(PersonProbuf.Person.PhoneType.HOME));

 

Person person = builder.build();

byte[] buf = person.toByteArray();

 

try {

Person person2 = PersonProbuf.Person.parseFrom(buf);

System.out.println(person2.getName() + “, ” + person2.getEmail());

List<PhoneNumber> lstPhones = person2.getPhoneList();

for (PhoneNumber phoneNumber : lstPhones) {

System.out.println(phoneNumber.getNumber());

}

} catch (InvalidProtocolBufferException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

System.out.println(buf);

 

}

 

}

 

源文档 <http://blog.csdn.net/csharp25/article/details/6632127>

通过admin

第2章 进程及进程调度

几个关键字:

进程结构task_struct;系统task_stuct数组;

进程状态:

进程时间片;

进程切换时,系统需要做那些保存操作;

进程创建过程,fork();

工作队列;

进程调度。

通过admin

《Linux内核分析及编程》第一章 数据类型及链表

本章完全是基础知识了,归纳下几点:

在不同的CPU体系结构上,C语言的数据类型所占的空间是不一样的;

为了方便移植,内核中很多数据类型由typedef声明;

内存页面大小;

字节对齐方式:低字节优先&高字节优先;

内核通用链表;

行内汇编的格式;

内核时间延迟;

通过admin

今天开始看《Linux内核分析及编程》

一直以来更多的是负责windows客户端的开发,对linux不是特别熟悉,不过后续的可能会更多的接触系统底层实现,所以还是赶紧恶补一下操作系统底层相关的吧。从操作系统原理来讲,windows和linux总体思路上基本还是一致的,而且相比之下,开源的linux对于学习操作系统应该是更加合适的。

刚好身边有一本《Linux内核分析及编程》,最近项目也刚好告一个段落,处于一个缓冲期,就趁现在好好翻一翻吧。

总共800页,平均每天看40页左右,争取3周看完,由于只有业余时间看,本次看不求深究细节,目的是对操作系统的基本原理有个更系统和全面的认识,同时尽量纠正平时自己的一些误区。至于大部分细节,还是留到平时工作用到时再来仔细研究吧。

坚持记笔记和发blog。