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 使用的更多相关文章

  1. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  2. python通过protobuf实现rpc

    由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...

  3. Netty5使用自签证书实现SSL安全连接

    这次使用的Netty是最新的5.0 Alpha2版本,下载地址是:http://dl.bintray.com/netty/downloads/netty-5.0.0.Alpha2.tar.bz2,发布 ...

  4. Protobuf使用规范分享

    一.Protobuf 的优点 Protobuf 有如 XML,不过它更小.更快.也更简单.它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍.你可以定义自己的数据结构 ...

  5. java netty socket库和自定义C#socket库利用protobuf进行通信完整实例

    之前的文章讲述了socket通信的一些基本知识,已经本人自定义的C#版本的socket.和java netty 库的二次封装,但是没有真正的发表测试用例. 本文只是为了讲解利用protobuf 进行C ...

  6. 在Wcf中应用ProtoBuf替代默认的序列化器

    Google的ProtoBuf序列化器性能的牛逼已经有目共睹了,可以把它应用到Socket通讯,队列,Wcf中,身为dotnet程序员一边期待着不久后Grpc对dotnet core的支持更期待着Wc ...

  7. protobuf的编译安装

    github地址:https://github.com/google/protobuf支持多种语言,有多个语言的版本,本文采用的是在centos7下编译源码进行安装. github上有详细的安装说明: ...

  8. 编译protobuf的jar文件

    1.准备工作 需要到github上下载相应的文件,地址https://github.com/google/protobuf/releases protobuf有很多不同语言的版本,因为我们需要的是ja ...

  9. protobuf学习(2)-相关学习资料

    protobuf官方git地址 protobuf官方英文文档   (你懂的需要FQ) protobuf中文翻译文档 protobuf概述          (官方翻译 推荐阅读) protobuf入门 ...

随机推荐

  1. 判断输入的数是否为数字,不使用isNaN

    虽然不使用 isNaN ,但使用了 Math 的一些方法. <!-- Author: XiaoWen Create a file: 2016-12-08 11:14:34 Last modifi ...

  2. Atitti.java exp ast java表达式语法ast构造器

    Atitti.java exp ast java表达式语法ast构造器 /atiplat_cms/src/com/attilax/lang/AstParser.java 原理 分割tokens_sli ...

  3. javaweb学习总结(八)——HttpServletResponse对象(二)

    一.HttpServletResponse常见应用——生成验证码 1.1.生成随机图片用作验证码 生成图片主要用到了一个BufferedImage类,

  4. 前端框架layui

    可以了解下jQuery组件layer layui开始使用Layui兼容除IE6/7以外的全部浏览器,并且绝大多数结构支持响应式 弹出层如果你使用的是Layui,那么你直接在官网下载layui框架即可, ...

  5. Ceph monitor故障恢复探讨

    1 问题 一般来说,在实际运行中,ceph monitor的个数是2n+1(n>=0)个,在线上至少3个,只要正常的节点数>=n+1,ceph的paxos算法能保证系统的正常运行.所以,对 ...

  6. Java线程与Linux内核线程的映射关系[转]

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  7. 求n*m网格内矩形的数目

    一个n*m的网格,求这个网格中矩形的数目. 比如以下2*2网格,总共有9个矩形:4个1*1的矩形,4个1*2的矩形,1个2*2的矩形   算法1:动态规划,假设dp[i][j]表示以第 i 行第 j ...

  8. 深入分析Java Web技术(2) IO

    IO是当今Web面临的主要问题之一,可以说,大部分web应用的瓶颈都是IO的瓶颈. Java的IO类是java.io.它包含有80多个类,分为4大部分: 基于字节操作: InputStream,Out ...

  9. 源代码安装 MySQL 5.6.28

    本文内容 创建 MySQL 用户和组 解压 MySQL 源代码包 生成配置安装文件 编译和安装 MySQL 配置文件 创建 MySQL 授权表 MySQL 目录授权 启动 MySQL 验证 MySQL ...

  10. ThinkCMF 解决xss攻击问题

    最近使用ThinkCMF给某政府开发的一个平台,因为他们需要通过国家二级信息安全等级测试 所以自己先使用Appscan测试了一下,结果扫描出一个xss安全问题 测试的网址:http://www.xxx ...