Netty5 + Protobuf 使用
1. 安装开发环境
1.1 Netty环境
这里我使用Netty5.0.0版本 到这里下载即可http://netty.io/ 下载netty-all-5.0.0.Alpha2.jar 这个jar包简单配置一下即可使用。
1.2 Protobuf环境
这个就比较麻烦了,这里说一下我的做法。 可以在这里下载最新版https://github.com/google/protobuf 或者使用 v2.6.1稳定版 https://github.com/google/protobuf/tree/v2.6.1
也可以在这里下载http://pkgs.fedoraproject.org/repo/pkgs/protobuf/protobuf-2.6.1.tar.bz2/
在这里下载对应的Protobuf-java.jar http://central.maven.org/maven2/com/google/protobuf/protobuf-java/
http://mvnrepository.com/artifact/com.google.protobuf/protobuf-java
1.3 Protoc 工具
Linux和Windows都差不多,编译源代码即可。
以Windows为例,打开\protobuf-2.6.1\vsprojects\protobuf.sln

这样生成解决方案。

在Debug里面这些文件是有用的

2. protobuf初始化
SubscribeReq.proto
package netty;
option java_package = "com.jieli.nettytest.protobuf";
option java_outer_classname = "SubscribeReqProto"; message SubscribeReq{
required int32 subReqID = 1;
required string userName = 2;
required string productName = 3;
repeated string address = 4;
}
SubscribeResq.proto
package netty;
option java_package = "com.jieli.nettytest.protobuf";
option java_outer_classname = "SubscribeResqProto"; message SubscribeResq{
required int32 subReqID = 1;
required int32 respCode = 2;
required string desc = 3;
}
用protobuf.exe进行编译
protoc.exe --java_out=. --cpp_out=. SubscribeReq.proto
protoc.exe --java_out=. --cpp_out=. SubscribeResq.proto
3. Protobuf 测试
TestSubscribeReqProto.java
package com.jieli.nettytest.protobuf; import java.util.ArrayList;
import java.util.List;
import com.google.protobuf.InvalidProtocolBufferException; public class TestSubscribeReqProto { private static byte[] encode(SubscribeReqProto.SubscribeReq req){
return req.toByteArray();
} private static SubscribeReqProto.SubscribeReq decode(byte[] body)
throws InvalidProtocolBufferException {
return SubscribeReqProto.SubscribeReq.parseFrom(body);
} private static SubscribeReqProto.SubscribeReq createSubscribeReq(){
SubscribeReqProto.SubscribeReq.Builder builder =
SubscribeReqProto.SubscribeReq.newBuilder();
builder.setSubReqID(1);
builder.setUserName("Lilinfeng");
builder.setProductName("netty book");
List<String> address = new ArrayList<>();
address.add("NanJing YuHuaTai");
address.add("beijin lilili");
address.add("asdfasdf");
builder.addAllAddress(address);
return builder.build();
} public static void main(String[] args) {
try {
SubscribeReqProto.SubscribeReq req = createSubscribeReq();
System.out.println("befor encode:" + req.toString());
SubscribeReqProto.SubscribeReq req2 = decode(encode(req));
System.out.println("After decode :"+req.toString());
System.out.println("assert equal : ==>" + req2.equals(req));
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果

项目目录结构

4. java-java通信例子(跟书本上是差不多一样的)
SubReqServer.java
package com.jieli.nettytest.protobuf; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
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; public class SubReqServer { public void bind(int port){
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
//与c++通信时这里的varint32要注释掉,因为默认的protobuf是没有32位对齐的,如果要实现自动分包,那么要在C++客户端进行组装
ch.pipeline().addLast(new ProtobufDecoder(
SubscribeReqProto.SubscribeReq.getDefaultInstance()));
ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new SubReqServerHandler());
}
}); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} public static void main(String[] args) {
new SubReqServer().bind(7777);
}
}
SubReqServerHandler.java
package com.jieli.nettytest.protobuf; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class SubReqServerHandler extends ChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
SubscribeReqProto.SubscribeReq req = (SubscribeReqProto.SubscribeReq) msg;
if("Lilinfeng".equalsIgnoreCase(req.getUserName())){
System.out.println("Service accept client subscribe req:["+req.toString()+"]");
//ctx.writeAndFlush(resp(req.getSubReqID()));
}
} private SubscribeResqProto.SubscribeResq resp(int subReqID){
SubscribeResqProto.SubscribeResq.Builder builder =
SubscribeResqProto.SubscribeResq.newBuilder();
builder.setSubReqID(subReqID);
builder.setRespCode(0);
builder.setDesc("Netty book order success..");
return builder.build();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
}
}
SubReqClient.java
package com.jieli.nettytest.protobuf; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; public class SubReqClient { public void connect(int port, String host){
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(new ProtobufDecoder(
SubscribeResqProto.SubscribeResq.getDefaultInstance()));
ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new SubReqClientHandler());
}
}); ChannelFuture f = b.connect(host, port).sync(); f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
} public static void main(String[] args) {
new SubReqClient().connect(7777, "localhost");
}
}
SubReqClientHandler.java
package com.jieli.nettytest.protobuf; import java.util.ArrayList;
import java.util.List; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class SubReqClientHandler extends ChannelHandlerAdapter{
public SubReqClientHandler() {
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for(int i=0; i<10; i++){
ctx.write(subReq(i));
}
ctx.flush();
} private SubscribeReqProto.SubscribeReq subReq(int i){
SubscribeReqProto.SubscribeReq.Builder builder =
SubscribeReqProto.SubscribeReq.newBuilder();
builder.setSubReqID(i);
builder.setUserName("Lilinfeng");
builder.setProductName("Netty Book..");
List<String> address = new ArrayList<>();
address.add("NanJin LLLLLL");
address.add("beijin lllllll");
address.add("shenzhen jjjjjj");
builder.addAllAddress(address);
return builder.build();
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("Receive server response:["+msg+"]");
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} }
服务器运行结果

客户端运行结果

5. (C/C++)-java通信例子
本来想用mingw来实现的但是,试了几次,总是编译不过。就放弃了,使用VS2008来编译了。
新建一个控制台程序,配置下属性页, 下面这个图配置到protobuf源代码的src目录

下面这个图配置到用vs编译编译产生的中间文件,包含几个lib包的目录

将经过protoc.exe产生的*.h和*.cc文件放到对应的项目中

main.cpp代码
#include <iostream>
#include <windows.h>
#include "SubscribeReq.pb.h"
#include "SubscribeResq.pb.h" #pragma comment(lib, "ws2_32.lib")
#pragma comment(lib,"libprotobuf.lib")
#pragma comment(lib,"libprotobuf-lite.lib") using namespace std;
using namespace netty; //打开连接
SOCKET open_msg(char *host, int port)
{
//初始化Socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(,);
if(WSAStartup(socketVersion,&wsaData)!=)
{
printf("Init socket dll error!");
return -;
}
//创建socket
SOCKET s = socket(AF_INET, SOCK_STREAM, ); //tcp
if (SOCKET_ERROR == s)
{
printf("Create Socket Error!");
return -;
}
//指定服务端的地址
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(host);
server_addr.sin_port = htons(port); char opt = ;
int ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(char));
if(ret == -)
{
printf("ERROR\n");
return -;
} //连接
if (SOCKET_ERROR == connect(s, (LPSOCKADDR)&server_addr, sizeof(server_addr)))
{
printf("Can Not Connect To Server IP!\n");
return -;
}
return s;
}
//获取信息
int recv_msg(SOCKET s,char *msg,int size)
{
int ret = recv(s,msg,size,);
if(ret == SOCKET_ERROR)
{
printf("Recv Error.\n");
return -;
}
return ret;
}
//发送信息
int send_msg(SOCKET s,char *msg,int size)
{
int ret = send(s,msg,size,);
if(ret == SOCKET_ERROR)
{
printf("Send Error.\n");
return -;
}
return ret;
}
//关闭连接
int close_msg(SOCKET s)
{
closesocket(s);
return ;
} int main()
{
SubscribeReq req ;
req.set_username("Lilinfeng");
req.add_address("asdf");
req.set_subreqid();
req.set_productname("laskjdfk111"); SOCKET s = open_msg("127.0.0.1", ); char msg[] = {};
req.SerializePartialToArray(msg, ); cout<<req.GetCachedSize()<<endl;
send_msg(s, msg, req.GetCachedSize()); close_msg(s); system("pause");
return ;
}
然后编译运行就可以发送protobuf对象到java服务器端,运行后服务器出现这个结果

找了很久原因,原来是服务器SubReqServer.java中的ProtobufVarint32***解码器对Protobuf包进行处理,导致格式不一致,解决的办法是注释掉这两行,不过这样又会产生书本上说到的问题,会出现粘包。我能想到的办法是1.在C++客户端中进行修改,使之对应到Java中对齐格式,这个要看源代码。 2.发送的包前面增加包头,然后包头信息描述Protobuf大小。
参考资料
Netty权威指南 – 第八章 Google Protobuf 编解码
http://blog.csdn.net/majianfei1023/article/details/45371743
http://www.cnblogs.com/lidabo/p/3911456.html
本文地址: http://www.cnblogs.com/wunaozai/p/5236494.html
Netty5 + Protobuf 使用的更多相关文章
- netty5 HTTP协议栈浅析与实践
一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...
- python通过protobuf实现rpc
由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...
- Netty5使用自签证书实现SSL安全连接
这次使用的Netty是最新的5.0 Alpha2版本,下载地址是:http://dl.bintray.com/netty/downloads/netty-5.0.0.Alpha2.tar.bz2,发布 ...
- Protobuf使用规范分享
一.Protobuf 的优点 Protobuf 有如 XML,不过它更小.更快.也更简单.它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍.你可以定义自己的数据结构 ...
- java netty socket库和自定义C#socket库利用protobuf进行通信完整实例
之前的文章讲述了socket通信的一些基本知识,已经本人自定义的C#版本的socket.和java netty 库的二次封装,但是没有真正的发表测试用例. 本文只是为了讲解利用protobuf 进行C ...
- 在Wcf中应用ProtoBuf替代默认的序列化器
Google的ProtoBuf序列化器性能的牛逼已经有目共睹了,可以把它应用到Socket通讯,队列,Wcf中,身为dotnet程序员一边期待着不久后Grpc对dotnet core的支持更期待着Wc ...
- protobuf的编译安装
github地址:https://github.com/google/protobuf支持多种语言,有多个语言的版本,本文采用的是在centos7下编译源码进行安装. github上有详细的安装说明: ...
- 编译protobuf的jar文件
1.准备工作 需要到github上下载相应的文件,地址https://github.com/google/protobuf/releases protobuf有很多不同语言的版本,因为我们需要的是ja ...
- protobuf学习(2)-相关学习资料
protobuf官方git地址 protobuf官方英文文档 (你懂的需要FQ) protobuf中文翻译文档 protobuf概述 (官方翻译 推荐阅读) protobuf入门 ...
随机推荐
- 判断输入的数是否为数字,不使用isNaN
虽然不使用 isNaN ,但使用了 Math 的一些方法. <!-- Author: XiaoWen Create a file: 2016-12-08 11:14:34 Last modifi ...
- Atitti.java exp ast java表达式语法ast构造器
Atitti.java exp ast java表达式语法ast构造器 /atiplat_cms/src/com/attilax/lang/AstParser.java 原理 分割tokens_sli ...
- javaweb学习总结(八)——HttpServletResponse对象(二)
一.HttpServletResponse常见应用——生成验证码 1.1.生成随机图片用作验证码 生成图片主要用到了一个BufferedImage类,
- 前端框架layui
可以了解下jQuery组件layer layui开始使用Layui兼容除IE6/7以外的全部浏览器,并且绝大多数结构支持响应式 弹出层如果你使用的是Layui,那么你直接在官网下载layui框架即可, ...
- Ceph monitor故障恢复探讨
1 问题 一般来说,在实际运行中,ceph monitor的个数是2n+1(n>=0)个,在线上至少3个,只要正常的节点数>=n+1,ceph的paxos算法能保证系统的正常运行.所以,对 ...
- Java线程与Linux内核线程的映射关系[转]
Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...
- 求n*m网格内矩形的数目
一个n*m的网格,求这个网格中矩形的数目. 比如以下2*2网格,总共有9个矩形:4个1*1的矩形,4个1*2的矩形,1个2*2的矩形 算法1:动态规划,假设dp[i][j]表示以第 i 行第 j ...
- 深入分析Java Web技术(2) IO
IO是当今Web面临的主要问题之一,可以说,大部分web应用的瓶颈都是IO的瓶颈. Java的IO类是java.io.它包含有80多个类,分为4大部分: 基于字节操作: InputStream,Out ...
- 源代码安装 MySQL 5.6.28
本文内容 创建 MySQL 用户和组 解压 MySQL 源代码包 生成配置安装文件 编译和安装 MySQL 配置文件 创建 MySQL 授权表 MySQL 目录授权 启动 MySQL 验证 MySQL ...
- ThinkCMF 解决xss攻击问题
最近使用ThinkCMF给某政府开发的一个平台,因为他们需要通过国家二级信息安全等级测试 所以自己先使用Appscan测试了一下,结果扫描出一个xss安全问题 测试的网址:http://www.xxx ...