用protobuf进行C#与Java通信
在之前已写一篇关于ProtoBuf的文章了,主要是.net版本的实现。今天主要是讲如何利用ProtoBuf定义一个协议,来实现C#与Java双方进行通信(这个通信指的是双方数据协议,而不是通信协议。)
ProtoBuf 应用场景
个人认为,主要用于数据交互和共享,此种情况需要双方制定一个特定的数据结构。那么使用ProtoBuf 定义一个数据结构,然后大家从这个描述文件,各自生成自己使用的编程语言对应的代码文件,再使用这些代码对双方的数据进行处理。那么,只要都遵守这个数据文件格式,数据共享就可以实现夸平台。如果数据描述文件做了修改,只要遵守一定的规则,那么原有数据还是可以兼容使用的。这个就是做了一个平台无关的文件与平台和语言相关的数据对象之间的适配转化工作,就和很多xml解析器一样。
实现C#与Java通信步骤
1.定义协议
创建一个以.proto为后缀的文件,本篇创建了一个名为msg.proto的消息文件,具体信息如下:
package tutorial;
option java_package = "com.protobuftest.protobuf"; (生成Java类时包名;C#类的命名空间)
option java_outer_classname = "PersonProbuf"; (生成Java、C#类的类名)
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;
}
package在Java里面代表这个文件所在的包名,在c#里面代表该文件的命名空间;
message代表一个类;
required 代表该字段必填;
optional 代表该字段可选,并可以为其设置默认值,默认值格式 :[defalut=Home],它是一个枚举类型。
2.双方都编译.proto文件(本篇文章主要用的是2.4.1版本的protobuf)
proto可以在Linux、Windows下编译。
protobuf 下载列表请参照:http://code.google.com/p/protobuf/downloads/list ,选择其中的win版本下载。解压后会得到一个 protoc.exe 文件,此时就可以开始编译了。
java 的编译的步骤如下:
(1) 打开命令工具 cmd
(2) 把protoc.exe文件放在D:/protoc 目录下,先cd 到该目录cd D:/protoc
(3) 输入protoc.exe --java_out=./ msg.proto
此时会发现 D:/protoc目录中多了一个文件夹com\protobuftest\protobuf,即以该proto的package命名的目录,会产生一个Msg.java的文件,这时这个文件就可以使用到我们的java或者android 工程了。
(4) 下载一个protobuf-java-2.4.1.jar的jar 包引用到你的java和android工程里面,之后可以使用你的protobuf了。
C# 的编译步骤:
.net 版的protobuf来源于proto社区,有两个版本。一个版本叫protobuf-net,官方站点:http://code.google.com/p/protobuf-net/ 写法上比较符合c#一贯的写法。
另一个版本叫protobuf-csharp-sport , 官方站点:http://code.google.com/p/protobuf-csharp-port/ 写法上跟java上的使用极其相似,比较遵循Google 的原生态写法,跨平台选择此版本比较好。因为你会发现几乎和java的写法没啥两样,本篇也是使用这个版本。
http://code.google.com/p/protobuf-csharp-port/下载Win版本,编译步骤如下:
(1) 把proto文件放在你解压出来的目录与protoc.exe 、ProtoGen.exe、ProtoGen.exe.config、Google.ProtocolBuffers.dll放于一起。其他文件可以删除或者备份。
(2) 打开命令行cmd,定位于对应的目录里面。
输入:protoc --descriptor_set_out=msg.protobin --include_imports msg.proto
msg.protobin是要生成的prtobobin文件,可以使用这个bin文件生成cs文件
再输入protogen msg.protobin 使用该bin文件生成cs文件,这样你就可以得到该msg.cs 的CSharp版文件了,同时在VS里面使用要引入Google.ProtocolBuffers.dll。为了方便你可以将其做成一个批处理文件代码如下:
echo on
protoc --descriptor_set_out=msg.protobin --include_imports msg.proto
protogen msg.protobin
将其另存为.bat文件即
3.Java代码如下:
package test;
import java.util.List;
import com.google.protobuf.InvalidProtocolBufferException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.Runtime;
import java.io.IOException;
public class ActivityMain {
public static void main(String[] args) {
serializable()
}
public static void serializable() {
// 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));
PersonProbuf.Person person = builder.build();
byte[] buf = person.toByteArray();
//反序列化
try {
PersonProbuf.Person person2 = PersonProbuf.Person.parseFrom(buf);
System.out.println(person2.getId()+","+person2.getName() + ", " + person2.getEmail());
List<PersonProbuf.Person.PhoneNumber> lstPhones = person2.getPhoneList();
for(PersonProbuf.Person.PhoneNumber phoneNumber : lstPhones) {
System.out.println(phoneNumber.getNumber());
}
} catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Finish");
}
}
4.C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.ProtocolBuffers;
using tutorial;
namespace ProtobufCSharp
{
class Program
{
static void Main(string[] args)
{
//序列化
Person.Builder builder = new Person.Builder();
builder.SetEmail("kkk@email.com");
builder.SetId(1);
builder.SetName("TestName");
builder.AddPhone(new Person.Types.PhoneNumber.Builder().SetNumber("131111111").SetType(Person.Types.PhoneType.MOBILE));
builder.AddPhone(new Person.Types.PhoneNumber.Builder().SetNumber("011111").SetType(Person.Types.PhoneType.HOME));
Person person = builder.Build();
byte[] buf = person.ToByteArray();
//反序列化
try {
Person person2 = Person.ParseFrom(buf);
Console.WriteLine(person2.Id+","+person2.Name + ", " + person2.Email);
IList<Person.Types.PhoneNumber> lstPhones = person2.PhoneList;
foreach(Person.Types.PhoneNumber phoneNumber in lstPhones)
{
Console.WriteLine(phoneNumber.Number);
}
} catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block
Console.WriteLine(e.Message);
}
Console.WriteLine("Finish");
Console.ReadKey();
}
}
}
上面的代码可以使用Socket、http、WebSerice等进行通信,发送\接收双方的数据(具体的数据协议从代码中可以看出)。具体的代码在这里就不在写了。
下面简单的概述一下Protobuf的优缺点:
优点
1. 定于语言体积小,支持多种数据类型,如list,支持嵌套
2. 定义过程中可以使用类型的概念,可以在使用的时候检查类型合法性
3. 可以将一个描述文件,生成多种语言的代码,使数据的读写实现了语言无关。
4. 如果描述文件修改了,只要遵守一定的规则,那原有数据结构对应的数据,也是可以被成功读取的。
缺点
1. 序列化后的文件不可读(因为是二进制数据)。
2. 不可与xml或者json进行相互转化。
http://hi.baidu.com/jack1865/item/366f2d305a722603b3c0c557
http://www.cnblogs.com/TerryBlog/archive/2011/04/23/2025654.html
android与PC,C#与Java 利用protobuf 进行无障碍通讯【Socket】