根据上一篇博文 Google Protobuf 使用 Java 版 netty 集成 protobuf 的方法非常简单.代码如下:

server

package protobuf.server.impl;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import object.server.impl.SubReqServer;
import object.server.impl.SubScriptReqProto; public class SubReqProtobufServer {
public void start(int port) {
NioEventLoopGroup workGroup = new NioEventLoopGroup();
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workGroup);
bootstrap.channel(NioServerSocketChannel.class);
// 配置 NioServerSocketChannel 的 tcp 参数, BACKLOG 的大小
bootstrap.option(ChannelOption.SO_BACKLOG, 100);
bootstrap.handler(new LoggingHandler(LogLevel.INFO));
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception { /*
* 首先添加 ProtobufVarint32FrameDecoder 处理器 , 它主要用于半包处理
*/
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
/*
* 然后添加 ProtobufDecoder 解码器 ,
* 他的参数com.google.protobuf.MessageLite 实际上就是要告诉 ProtobufDecoder
* 需要解码的目标类是什么,否则仅仅从字节数组中是无法判断出需要解码的目标类型信息
*/
ProtobufDecoder protobufDecoder = new ProtobufDecoder(
SubScriptReqProto.SubScriptReq.getDefaultInstance());
ch.pipeline().addLast(protobufDecoder);
ch.pipeline().addLast(
new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new SubReqProtobufHandler());
}
});
// 绑定端口,随后调用它的同步阻塞方法 sync 等等绑定操作成功,完成之后 Netty 会返回一个 ChannelFuture
// 它的功能类似于的 Future,主要用于异步操作的通知回调.
ChannelFuture channelFuture;
try {
channelFuture = bootstrap.bind(port).sync();
// 等待服务端监听端口关闭,调用 sync 方法进行阻塞,等待服务端链路关闭之后 main 函数才退出.
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
} public static void main(String[] args) {
SubReqProtobufServer server = new SubReqProtobufServer();
server.start(9091);
}
}

serverHandler

package protobuf.server.impl;

import object.server.impl.SubScriptReqProto;
import object.server.impl.SubScriptRespProto;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class SubReqProtobufHandler extends ChannelHandlerAdapter { @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
try { SubScriptReqProto.SubScriptReq req = (SubScriptReqProto.SubScriptReq) msg;
System.out.println("SubReqProtobufHandler : " + req);
ctx.writeAndFlush(resp(req.getSubReqID()));
} catch (Exception e) {
e.printStackTrace();
throw e;
}
} private Object resp(int subReqID) {
SubScriptRespProto.SubScriptResp.Builder builder = SubScriptRespProto.SubScriptResp
.newBuilder();
builder.setSubReqID(subReqID);
builder.setDesc("desc");
builder.setRespCode(2);
return builder.build();
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} }

client

package protobuf.client.impl;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.codec.serialization.ObjectEncoder;
import object.client.impl.SubReqClient;
import object.server.impl.SubScriptReqProto;
import object.server.impl.SubScriptRespProto; public class SubReqProtobufClient {
public void connect(String host, int port) {
NioEventLoopGroup workGroup = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
/*
* 禁止堆类加载器进行缓存,他在基于 OSGI 的动态模块化编程中经常使用,由于 OSGI 可以进行热部署和热升级,当某个
* bundle
* 升级后,它对应的类加载器也将一起升级,因此在动态模块化的编程过程中,很少对类加载器进行缓存,因为他随时可能会发生变化.
*/
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(
new ProtobufDecoder(SubScriptRespProto.SubScriptResp
.getDefaultInstance()));
ch.pipeline().addLast(
new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new SubReqClientHandler());
}
}); // 发起异步链接操作
ChannelFuture future;
try {
future = bootstrap.connect(host, port).sync();
// 等待客户端链路关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workGroup.shutdownGracefully();
}
} public static void main(String[] args) {
new SubReqProtobufClient().connect("localhost", 9091);
}
}

clientHandler

package protobuf.client.impl;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import object.server.impl.SubScriptReqProto; public class SubReqClientHandler extends ChannelHandlerAdapter { @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
try { SubScriptReqProto.SubScriptReq.Builder builder = SubScriptReqProto.SubScriptReq
.newBuilder();
for (int i = 0; i < 100; i++) { builder.setSubReqID(999 + i);
builder.setAddress("address" + i);
builder.setProductName("productvalue" + i);
builder.setUserName("userName" + i); ctx.writeAndFlush(builder.build());
}
} catch (Exception e) {
e.printStackTrace();
}
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("SubReqClientHandler : " + msg);
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} }

使用 ProtoBuf 的注意事项:

  ProtobufDecode 只负责解码,它不支持半包读写,因此,在 protoBuf 前一定要一个能处理半包读写的处理器.他有三种方法可以选择:

  1. 使用 Netty 提供的 ProtobufVarint32FrameDecoder;
  2. 继承 Netty 提供的通用半包解码器 LengthFieldBasedFrameDecoder;
  3. 继承 ByteToMessageDecoder 类,自己处理半包消息

  

以上内容出自 : <Netty 权威指南

>

netty 的 Google protobuf 开发的更多相关文章

  1. Netty学习——Google Protobuf使用方式分析和环境搭建

    Google Protobuf使用方式分析 在RPC框架中,Google Protobuf是很常用的一个库,和Apache Thrift 是同款的用于进行序列化的第三方库.原理都是大同小异,无非就是使 ...

  2. Netty学习——Google Protobuf的初步了解

    学习参考的官网: https://developers.google.com/protocol-buffers/docs/javatutorial 简单指南详解:这个文档写的简直是太详细了. 本篇从下 ...

  3. google protobuf学习笔记:windows下环境配置

    欢迎转载,转载请注明原文地址:http://blog.csdn.net/majianfei1023/article/details/45371743 protobuf的使用和原理,请查看:http:/ ...

  4. (中级篇 NettyNIO编解码开发)第八章-Google Protobuf 编解码-2

    8.1.2    Protobuf编解码开发 Protobuf的类库使用比较简单,下面我们就通过对SubscrjbeReqProto进行编解码来介绍Protobuf的使用. 8-1    Protob ...

  5. (中级篇 NettyNIO编解码开发)第八章-Google Protobuf 编解码-1

    Google的Protobuf在业界非常流行,很多商业项目选择Protobuf作为编解码框架,这里一起回顾一下Protobuf    的优点.(1)在谷歌内部长期使用,产品成熟度高:(2)跨语言,支持 ...

  6. Netty使用Google的ProtoBuf

    protobuf是由Google开发的一套对数据结构进行序列化的方法,可用做通信协议,数据存储格式,等等.其特点是不限语言.不限平台.扩展性强 Netty也提供了对Protobuf的天然支持,我们今天 ...

  7. 《精通并发与Netty》学习笔记(05 - Google Protobuf与Netty的结合)

    protobuf是由Google开发的一套对数据结构进行序列化的方法,可用做通信协议,数据存储格式,等等.其特点是不限语言.不限平台.扩展性强 Netty也提供了对Protobuf的天然支持,我们今天 ...

  8. 《精通并发与Netty》学习笔记(04 - Google Protobuf介绍)

    一 .Google Protobuf 介绍 protobuf是google团队开发的用于高效存储和读取结构化数据的工具,是Google的编解码技术,在业界十分流行,通过代码生成工具可以生成不同语言版本 ...

  9. Google Protobuf结合Netty实践

    1.Win版Protobuf代码生成工具下载: https://github.com/protocolbuffers/protobuf/releases 注意下载protoc-3.6.1-win32. ...

随机推荐

  1. Linux硬盘管理

    管理好硬盘/dev/xxynsd SCSI SATA USBhd IDE主分区扩展分区 1-4逻辑分区5以后fdisk -l 硬盘名/分区名fdisk -l /dev/sda 如何给硬盘分区?把500 ...

  2. redis:order set有序集合类型的操作(有序集合)

    1. order set有序集合类型的操作(有序集合) 有序集合是在无序集合的基础上加了一个排序的依据,这个排序依据叫score,因此声明一个集合为有序集合的时候要加上score(作为排序的依据) 1 ...

  3. Spring MVC4 + Spring Security4 + Hibernate实例

    http://www.yiibai.com/spring-security/spring-mvc-4-and-spring-security-4-integration-example.html 在这 ...

  4. idea其他人把jar更新之后更新不到

    昨天下午开始就发现这个问题,其他同事把jar更新了之后,我一直获取不到更新之后的内容.尝试了很多方法,删除具体的更新不到的jar,一直不停的mvn clean install -U -Dmaven.t ...

  5. angular-环境搭建

    angular环境搭建(angular-cli) 1.安装nodejs http://nodejs.cn/download/ 2.Angular命令行工具安装 npm install -g @angu ...

  6. SQL学习1:基础

    SQL 是用于访问和处理数据库的标准的计算机语言. SQL,指结构化查询语言,全称是 Structured Query Language. SQL 能做什么? SQL 面向数据库执行查询 SQL 可从 ...

  7. C# 实现Remoting双向通信

    本篇文章主要介绍了C# 实现Remoting双向通信,.Net Remoting 是由客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象来实现通信的 闲来无事想玩玩双向通 ...

  8. ELK架构设计

    1.架构一 2.架构二 3.架构三 4.架构四 示例1: 示例二: ELKB简述 E:Elasticsearch 是一个基于Lucene的分布式搜索和分析引擎,具有高可伸缩.高可靠和易管理等特点.支持 ...

  9. 如何在一小时内更新100篇文章?-Evernote Sync插件介绍

    上一篇"手把手教你制作微信小程序,开源.免费.快速搞定",已经教会你如何快速制作一个小程序,但作为资讯类小程序,内容不可少,并且还需要及时更新. 但是,如果让你复制粘贴,可能还需要 ...

  10. 使用Træfɪk(traefik)来加速Qt在线更新

    简述 在使用Qt的MaintenanceTool程序进行在线更新的时候遇到一个问题,就是访问download.qt.io实在太慢了,老是失败.所以想使用国内的镜像站来进行更新. 使用Qt的镜像站方法也 ...