http://my.oschina.net/xinxingegeya/blog/295031java
上一篇瞭解了protobuf,如今結合netty作一個例子。bootstrap
關鍵就是配置netty的編解碼器,由於netty提供了protobuf的編解碼器,因此咱們能夠很容易的使用netty提供的編解碼器使用protobuf數據交換協議進行通訊。。服務器
下面是示例代碼,對於瞭解的netty的同窗應該不難看懂。socket
ProtobufNettyServer.javaide
package com.example.tutorial; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import telnet.TelnetServerInitializer; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-7-22 * Time: 下午8:26 * To change this template use File | Settings | File Templates. */ public class ProtobufNettyServer { private final int port; public ProtobufNettyServer(int port) { this.port = port; } public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ProtobufNettyServerInitializer()); b.bind(port).sync().channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8999; } new ProtobufNettyServer(port).run(); } }
ProtobufNettyServerInitializer.javaoop
package com.example.tutorial; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.protobuf.ProtobufDecoder; import io.netty.handler.codec.protobuf.ProtobufEncoder; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-7-22 * Time: 下午8:46 * To change this template use File | Settings | File Templates. */ public class ProtobufNettyServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); pipeline.addLast("protobufEncoder", new ProtobufEncoder()); pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4)); pipeline.addLast("protobufDecoder", new ProtobufDecoder( AddressBookProtos.AddressBook.getDefaultInstance())); pipeline.addLast("protobufHandler", new ProtobufNettyServerHandler()); } }
ProtobufNettyServerHandler.javaui
package com.example.tutorial; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-7-22 * Time: 下午9:19 * To change this template use File | Settings | File Templates. */ public class ProtobufNettyServerHandler extends SimpleChannelInboundHandler<AddressBookProtos.AddressBook> { @Override protected void channelRead0(ChannelHandlerContext ctx, AddressBookProtos.AddressBook msg) throws Exception { System.out.println("服務器端接受到的數據是:" + msg.toString()); AddressBookProtos.Person person = msg.getPerson(0); //把電話薄中的第一我的返回給客戶端 ctx.channel().writeAndFlush(person); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); //To change body of overridden methods use File | Settings | File Templates. } }
ProtobufNettyClient.javathis
package com.example.tutorial; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-7-22 * Time: 下午9:18 * To change this template use File | Settings | File Templates. */ public class ProtobufNettyClient { private final String host; private final int port; public ProtobufNettyClient(String host, int port) { this.host = host; this.port = port; } public void run() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ProtobufNettyClientInitializer()); ChannelFuture f = b.connect(host, port).sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length != 2) { System.err.println("Usage: " + ProtobufNettyClient.class.getSimpleName() + " <host> <port>"); return; } // Parse options. String host = args[0]; int port = Integer.parseInt(args[1]); new ProtobufNettyClient(host, port).run(); } }
ProtobufNettyClientInitializer.javaspa
package com.example.tutorial; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.protobuf.ProtobufDecoder; import io.netty.handler.codec.protobuf.ProtobufEncoder; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-7-22 * Time: 下午9:18 * To change this template use File | Settings | File Templates. */ public class ProtobufNettyClientInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); pipeline.addLast("protobufEncoder", new ProtobufEncoder()); pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4)); pipeline.addLast("protobufDecoder", new ProtobufDecoder( AddressBookProtos.Person.getDefaultInstance())); pipeline.addLast("protobufHandler", new ProtobufNettyClientHandler()); } }
ProtobufNettyClientHandler.java.net
package com.example.tutorial; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; public class ProtobufNettyClientHandler extends SimpleChannelInboundHandler<AddressBookProtos.Person> { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { AddressBookProtos.AddressBook.Builder addressBookBuilder = AddressBookProtos.AddressBook.newBuilder(); AddressBookProtos.Person.PhoneNumber.Builder phoneNumberBuilder = AddressBookProtos. Person.PhoneNumber.newBuilder(); AddressBookProtos.Person.Builder personBuilder = AddressBookProtos.Person.newBuilder(); personBuilder.setEmail("744858873@qq.com").setId(123456789).setName("hellolyx"); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330465").setType(AddressBookProtos.Person.PhoneType.HOME).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330466").setType(AddressBookProtos.Person.PhoneType.WORK).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330467").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330468").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330469").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.setPhone(0, phoneNumberBuilder.setNumber("110").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); //向電話薄裏添加一個聯繫人 addressBookBuilder.addPerson(personBuilder.build()); personBuilder.setEmail("78655676@qq.com").setId(123456789).setName("hellodog"); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330465").setType(AddressBookProtos.Person.PhoneType.HOME).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330466").setType(AddressBookProtos.Person.PhoneType.WORK).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330467").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330468").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330469").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.setPhone(0, phoneNumberBuilder.setNumber("119").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); //再次向電話薄裏添加一個聯繫人 addressBookBuilder.addPerson(personBuilder.build()); personBuilder.setEmail("78655676@qq.com").setId(123456789).setName("hellopig"); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330465").setType(AddressBookProtos.Person.PhoneType.HOME).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330466").setType(AddressBookProtos.Person.PhoneType.WORK).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330467").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330468").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.addPhone(phoneNumberBuilder.setNumber("15840330469").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); personBuilder.setPhone(0, phoneNumberBuilder.setNumber("124").setType(AddressBookProtos.Person.PhoneType.MOBILE).build()); addressBookBuilder.addPerson(personBuilder.build()); /** * 一個電話薄裏添加了三我的 */ AddressBookProtos.AddressBook addressBook = addressBookBuilder.build(); ctx.channel().writeAndFlush(addressBook); } @Override protected void channelRead0(ChannelHandlerContext ctx, AddressBookProtos.Person msg) throws Exception { //打印接受到的數據 System.out.println(msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); //To change body of overridden methods use File | Settings | File Templates. } }
這就是所有的代碼了。關鍵就是編解碼的配置部分,
客戶端的解碼器必定要配置正確:
pipeline.addLast("protobufDecoder", new ProtobufDecoder( AddressBookProtos.Person.getDefaultInstance()));
===END===