http://my.oschina.net/xinxingegeya/blog/295031
上一篇了解了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("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===
来源:oschina
链接:https://my.oschina.net/u/1469576/blog/295032