上一篇了解了protobuf,现在结合netty做一个例子。
关键就是配置netty的编解码器,因为netty提供了protobuf的编解码器,所以我们可以很容易的使用netty提供的编解码器使用protobuf数据交换协议进行通信。。
下面是示例代码,对于了解的netty的同学应该不难看懂。。
服务器端程序:
ProtobufNettyServer.java
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.java
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.java
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.java
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.java
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
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("[email protected]").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("[email protected]").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("[email protected]").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===
Netty with protobuf(二)
时间: 2024-10-06 00:23:51