关闭

httpclient +protobuf 实现数据传输

4253人阅读 评论(1) 收藏 举报
分类:

最近项目要接入某联盟广告,采用protobuf作为传输协议,以前没弄过,这次刚好使用到了,整理下

一、环境准备:(mac下)

1.1 下载protobuf2.5安装包

[html] view plain copy
  1. http://pan.baidu.com/s/1o6v4Sae  
1.2 解压安装包

[html] view plain copy
  1. tar -zxf  protobuf-2.5.0.tar.gz  
1.3 进入软件目录

[html] view plain copy
  1. cd protobuf-2.5.0  
1.4 设置编译目录

[html] view plain copy
  1. ./configure --prefix=/User/jack/software/tools/protobuf  
  2.  /User/jack/software/tools/protobuf  为自己设定的编译安装目录  
1.5 安装

[html] view plain copy
  1. make  
  2. make install  
1.6 配置环境变量

[html] view plain copy
  1. sudo vi .bash_profile  
  2. export PROTOBUF=/Users/jack/software/tools/protobuf  
  3. export PATH=$PROTOBUF/bin:$PATH  
1.7 验证

[html] view plain copy
  1. jack-3:bin jack$ protoc --version  
  2. libprotoc 2.5.0  

二、代码编写

2.1 查看.proto文件,只贴出了部分文件内容

[html] view plain copy
  1. package mobads.apiv5;  
  2. // 本文件描述API接口版本:5.0.0  
  3.   
  4. // 版本号信息  
  5. message Version {  
  6.     optional uint32 major = 1[default = 0]; // 必填!  
  7.     optional uint32 minor = 2[default = 0]; // 选填!  
  8.     optional uint32 micro = 3[default = 0]; // 选填!  
  9. };  

2.2 下载 protobuf-java-2.5.0.jar

[html] view plain copy
  1. http://download.csdn.net/download/zinc2008/8128155  

2.3 生成.java文件

[html] view plain copy
  1. protoc --java_out=./ baidu_mobads_api_5.0.proto  

同样只贴出部分java源文件 ( 注意java文件不要修改哦)

[html] view plain copy
  1. // Generated by the protocol buffer compiler.  DO NOT EDIT!  
  2. // source: baidu_mobads_api_5.0.proto  
  3.   
  4. package mobads.apiv5;  
  5.   
  6. public final class BaiduMobadsApi50 {  
  7.   private BaiduMobadsApi50() {}  
  8. }  


2.4 代码编写,只贴出关键部分

[html] view plain copy
  1. MobadsRequest adrequest = MobadsRequest.newBuilder().setRequestId(requestId).setAdslot(adslot).build();  
  2.   
  3. byte[] content = adrequest.toByteArray();  
  4.           
  5. HttpClient client = new HttpClient();   
  6. PostMethod postMethod = new PostMethod(URL);    
  7. postMethod.addRequestHeader("Content-Type", "application/octet-stream;charset=utf-8");  
  8. postMethod.setRequestEntity(new ByteArrayRequestEntity(content ));    
  9. client.executeMethod(postMethod);    
  10.             

注意content-type 设置为application/octet-stream。


到此,就完成了通过httpclient的post请求传输protobuf二进制流。

使用protobuf,所有的参数和返回都是对象的形式,这点还是用着比较爽的。


String byte 切换方法

服务端返回字符串


方式一:

[java] view plain copy
  1. Arrays.toString(personInfo.toByteArray())  

方式二:

[java] view plain copy
  1. toByteString().toStringUtf8()  


客户端解析字符串

方式一:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private static byte[] fromString(String string) {  
  2.     String[] strings = string.replace("[""").replace("]""").split(", ");  
  3.     byte[] result = new byte[strings.length];  
  4.     for (int i = 0; i < result.length; i++) {  
  5.         result[i] = Byte.parseByte(strings[i]);  
  6.     }  
  7.     return result;  
  8. }  
  9.   
  10. XXX.parseFrom(fromString(byteString))  

方式二:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. XXX.parseFrom(ByteString.copyFromUtf8(utf8ByteString))  


protobuf已经出来好多年了,原谅我最近才了解到google这个高性能的用于传输的格式。

 

从各方面来看,它无论从序列化的性能还是从序列化的压缩比都是优于当前各种传输格式的。如json、xml、hessian,java原生的Serializable。具体对比结果参见:http://agapple.iteye.com/blog/859052

 

网上也看了些资料,并有所了解,看了下,这玩意儿性能上来说真的没什么可说,但初始化和使用的时候感觉不是特别方便。而且网上的例子多数都是序列化过程,没有很多关于演示网络传输的demo,于是自己简单写了一个,将完整的例子摆在这里。

 

先定义一个Person.proto

 

Java代码  收藏代码
  1. option java_package = "com.example.protobuf";  
  2. option java_outer_classname = "PersonProbuf";  
  3.   
  4. message Person {  
  5.   required string name = 1;  
  6.   required int32 id = 2;  
  7.   optional string email = 3;  
  8.   repeated PhoneNumber phone = 4;  
  9.   
  10.   enum PhoneType {  
  11.     MOBILE = 0;  
  12.     HOME = 1;  
  13.     WORK = 2;  
  14.   }  
  15.   
  16.   message PhoneNumber {  
  17.     required string number = 1;  
  18.     optional PhoneType type = 2 [default = HOME];  
  19.   }  
  20. }  

 使用protoc生成对应的PersonProtobuf类

 

 

Java代码  收藏代码
  1. protoc.exe Person.proto --java_out=.  

 

 

请求客户端代码如下:

 

Java代码  收藏代码
  1. PersonProbuf.Person.Builder personRequest = PersonProbuf.Person.newBuilder();  
  2. personRequest.setId(1);  
  3. personRequest.setName("jesse");  
  4. personRequest.setEmail("xx@xx.com");  
  5.         personRequest.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber("1234567890").setType(PersonProbuf.Person.PhoneType.HOME));  
  6.   
  7. //使用java原生URL连接代码生成请求并获得返回值打印          
  8. URL url = new URL("http://localhost:90/protobuf.jsp");  
  9. URLConnection connection = url.openConnection();  
  10. connection.setDoOutput(true);  
  11. personRequest.build().writeTo(connection.getOutputStream());  
  12.           
  13. PersonProbuf.Person personResponse = PersonProbuf.Person.parseFrom(connection.getInputStream());  
  14. System.out.println(personResponse.getId());  
  15. System.out.println(personResponse.getName());  
  16. System.out.println(personResponse.getEmail());  
  17. System.out.println(personResponse.getPhone(0));  
  18. System.out.println(personResponse.getPhone(1));  

  

服务端protobuf.jsp代码如下:

 

Java代码  收藏代码
  1. <%@ page pageEncoding="UTF-8"%>  
  2. <%@page import="com.example.protobuf.PersonProbuf"%>  
  3. <%  
  4. PersonProbuf.Person person = PersonProbuf.Person.parseFrom(request.getInputStream());  
  5. System.out.println(person.getId());  
  6. System.out.println(person.getName());  
  7. System.out.println(person.getEmail());  
  8. System.out.println(person.getPhone(0));  
  9. PersonProbuf.Person.Builder personBuilder = person.newBuilder(person);  
  10. personBuilder.setId(2);  
  11. personBuilder.setName("tiger");  
  12. personBuilder.setEmail("yy@yy.com");  
  13. personBuilder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber("0987654321").setType(PersonProbuf.Person.PhoneType.HOME));  
  14. personBuilder.build().writeTo(response.getOutputStream());  
  15. %>  

 

执行客户端代码后,服务端/客户端输出:

Java代码  收藏代码
  1. ------服务端输出------  
  2. 1  
  3. jesse  
  4. xx@xx.com  
  5. number: "1234567890"  
  6. type: HOME  
  7.   
  8. ------客户端输出------  
  9. 2  
  10. tiger  
  11. yy@yy.com  
  12. number: "1234567890"  
  13. type: HOME  
  14.   
  15. number: "0987654321"  
  16. type: MOBILE  

 

 

所以protobuf只是一种序列化的格式,并不是传输协议,需要传输的,只要使用输入输出流,就可以做任何保存,传输的操作。

 

另外百度写了个jprotobuf开源,使用起来挺方便,只要使用注解放在javabean上就可以了

github:https://github.com/jhunters/jprotobuf

不过这个开源工具对集合没有适合的注解,而且也没有说明和其他语言传输的时候,如何保证一致性,所以需要使用的人考虑清楚,需要慎用。


3
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:8242477次
    • 积分:70061
    • 等级:
    • 排名:第26名
    • 原创:256篇
    • 转载:2742篇
    • 译文:3篇
    • 评论:735条
    文章分类
    最新评论