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
1 package netty; 2 option java_package = "com.jieli.nettytest.protobuf"; 3 option java_outer_classname = "SubscribeReqProto"; 4 5 message SubscribeReq{ 6 required int32 subReqID = 1; 7 required string userName = 2; 8 required string productName = 3; 9 repeated string address = 4; 10 }
SubscribeResq.proto
1 package netty; 2 option java_package = "com.jieli.nettytest.protobuf"; 3 option java_outer_classname = "SubscribeResqProto"; 4 5 message SubscribeResq{ 6 required int32 subReqID = 1; 7 required int32 respCode = 2; 8 required string desc = 3; 9 }
用protobuf.exe进行编译
1 protoc.exe --java_out=. --cpp_out=. SubscribeReq.proto 2 protoc.exe --java_out=. --cpp_out=. SubscribeResq.proto
3. Protobuf 测试
TestSubscribeReqProto.java
1 package com.jieli.nettytest.protobuf; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import com.google.protobuf.InvalidProtocolBufferException; 6 7 public class TestSubscribeReqProto { 8 9 private static byte[] encode(SubscribeReqProto.SubscribeReq req){ 10 return req.toByteArray(); 11 } 12 13 private static SubscribeReqProto.SubscribeReq decode(byte[] body) 14 throws InvalidProtocolBufferException { 15 return SubscribeReqProto.SubscribeReq.parseFrom(body); 16 } 17 18 private static SubscribeReqProto.SubscribeReq createSubscribeReq(){ 19 SubscribeReqProto.SubscribeReq.Builder builder = 20 SubscribeReqProto.SubscribeReq.newBuilder(); 21 builder.setSubReqID(1); 22 builder.setUserName("Lilinfeng"); 23 builder.setProductName("netty book"); 24 List<String> address = new ArrayList<>(); 25 address.add("NanJing YuHuaTai"); 26 address.add("beijin lilili"); 27 address.add("asdfasdf"); 28 builder.addAllAddress(address); 29 return builder.build(); 30 } 31 32 public static void main(String[] args) { 33 try { 34 SubscribeReqProto.SubscribeReq req = createSubscribeReq(); 35 System.out.println("befor encode:" + req.toString()); 36 SubscribeReqProto.SubscribeReq req2 = decode(encode(req)); 37 System.out.println("After decode :"+req.toString()); 38 System.out.println("assert equal : ==>" + req2.equals(req)); 39 } catch (Exception e) { 40 e.printStackTrace(); 41 } 42 } 43 }
运行结果
项目目录结构
4. java-java通信例子(跟书本上是差不多一样的)
SubReqServer.java
1 package com.jieli.nettytest.protobuf; 2 3 import io.netty.bootstrap.ServerBootstrap; 4 import io.netty.channel.ChannelFuture; 5 import io.netty.channel.ChannelInitializer; 6 import io.netty.channel.ChannelOption; 7 import io.netty.channel.EventLoopGroup; 8 import io.netty.channel.nio.NioEventLoopGroup; 9 import io.netty.channel.socket.SocketChannel; 10 import io.netty.channel.socket.nio.NioServerSocketChannel; 11 import io.netty.handler.codec.protobuf.ProtobufDecoder; 12 import io.netty.handler.codec.protobuf.ProtobufEncoder; 13 import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 14 import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 15 import io.netty.handler.logging.LogLevel; 16 import io.netty.handler.logging.LoggingHandler; 17 18 public class SubReqServer { 19 20 public void bind(int port){ 21 EventLoopGroup bossGroup = new NioEventLoopGroup(); 22 EventLoopGroup workerGroup = new NioEventLoopGroup(); 23 try { 24 ServerBootstrap b = new ServerBootstrap(); 25 b.group(bossGroup, workerGroup) 26 .channel(NioServerSocketChannel.class) 27 .option(ChannelOption.SO_BACKLOG, 100) 28 .handler(new LoggingHandler(LogLevel.INFO)) 29 .childHandler(new ChannelInitializer<SocketChannel>() { 30 @Override 31 protected void initChannel(SocketChannel ch) throws Exception { 32 ch.pipeline().addLast(new ProtobufVarint32FrameDecoder()); 33 //与c++通信时这里的varint32要注释掉,因为默认的protobuf是没有32位对齐的,如果要实现自动分包,那么要在C++客户端进行组装 34 ch.pipeline().addLast(new ProtobufDecoder( 35 SubscribeReqProto.SubscribeReq.getDefaultInstance())); 36 ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender()); 37 ch.pipeline().addLast(new ProtobufEncoder()); 38 ch.pipeline().addLast(new SubReqServerHandler()); 39 } 40 }); 41 42 ChannelFuture f = b.bind(port).sync(); 43 44 f.channel().closeFuture().sync(); 45 } catch (Exception e) { 46 e.printStackTrace(); 47 } finally { 48 bossGroup.shutdownGracefully(); 49 workerGroup.shutdownGracefully(); 50 } 51 } 52 53 public static void main(String[] args) { 54 new SubReqServer().bind(7777); 55 } 56 }