本文档主要说明如何利用netty进行对象传输
2. 实现方案前提条件:对象须实现序列化。
基本思想:借助netty自带的ObjectDecoder和ObjectEncoder类实现对象序列化的传输
3. 参考源码包源码包:org.jboss.netty.handler.codec.serialization
3.1. ObjectDecoder
此类主要完成数据转换成对象操作,继承了LengthFieldBasedFrameDecoder类。
核心方法:
publicObjectDecoder(int maxObjectSize, ClassResolver classResolver) {
super(maxObjectSize, 0, 4, 0, 4);
this.classResolver = classResolver;
}
此构造方法为最核心的对象解码器
参数说明:
maxObjectSize:序列化的对象的最大长度,一旦接收到的对象长度大于此值,抛出StreamCorruptedException异常,默认为1048576
classResolver:这个类(ClassResolver)会去加载已序列化的对象,
常用调用方式:ClassResolvers.cacheDisabled(Plan.class.getClassLoader())
或者直接ClassResolvers.cacheDisabled(null)
3.2. ObjectEncoder
此类主要是完成对对象的编码操作,继承了OneToOneEncoder类。
核心方法:
public ObjectEncoder(intestimatedLength) {
ifestimatedLength
throw new IllegalArgumentException(
"estimatedLength: "estimatedLength);
}
this.estimatedLengthestimatedLength;
}
参数说明:
estimatedLength:预估的要编码的对象的大小,此值常常是我们经常发送的对象的大小,设置不宜过大或过小,设置的过大容易造成内存的浪费,设置过小容易造成要对一个对象编码时反复扩展容量,反复拷贝的内容消耗。
3.3. ObjectDecoderInputStream
当客户端采用了ObjectEncoder,而服务器段未采用ObjectDecoder,就需要用这个类进行转换,转换代码:
ChannelBufferChannelBuffer) e.getMessage();
Object obj = null;
ByteArrayInputStream bi = null;
ObjectDecoderInputStream oi = null;
try {
bi = new ByteArrayInputStream(cb.array());
oi = new ObjectDecoderInputStream(bi);
obj = oi.readObject();
} catch (Exception e2) {
LOGGER.error("byte数组转对象异常:"+e2);
} finally {
closeInStreamQuietly(bi);
closeInStreamQuietly(oi);
}
Plan plan = (Plan)obj;
LOGGER.info(plan);
plan.setStatus(" server received");
byte[] b = Utils.obj2Byte(plan);
ChannelBuffer backBuffer = ChannelBuffers.buffer(b.length);
backBuffer.writeBytes(b);
e.getChannel().write(backBuffer,e.getRemoteAddress());
3.4. ObjectEncoderOutputStream
当服务器端采用了ObjectDecoder,而客户端采用的是非Netty中的ObjectEncoder,则需要用这个类进行转换,转换方式类似于3.3
注意:采用此方法后仍然需要在pipelineFactory设置
new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)(解码端)
和new LengthFieldPrepender(4, false)(编码端)
Plan plan = newPlan();
plan.setAuthor("linfenliang");
plan.setContent("something about sequence");
plan.setDate("2012-11-07");
plan.setStatus("client send ");
byte[] b = Utils.obj2Byte(plan);
System.out.println(Utils.bytesToHex(b));
initChannel();
byte[] bytes = null;
ByteArrayOutputStream bo = null;
ObjectEncoderOutputStream oo = null;
try {
bo = new ByteArrayOutputStream();
oo = new ObjectEncoderOutputStream(bo);
oo.writeObject(plan);
bytes = bo.toByteArray();
} catch (Exception e) {
System.err.println("Object对象转byte数组异常:"+e);
} finally {
closeOutStreamQuietly(bo);
closeOutStreamQuietly(oo);
}
buffer(bytes.length);
cb.writeBytes(bytes);
channel.write(cb);
4. Demo实现源码详见压缩包
注意创建的自定义bean必须实现Serializable,且客户端与服务器段的bean名字必须完全相同包也必须相同
public class Plan implements Serializable…
4.1. UDPServerPipelineFactory
getPipeline()方法中
ChannelPipeline pipeline = Channels.pipeline(
// new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4),
// new LengthFieldPrepender(4, false),
newcacheDisabled(Plan.class.getClassLoader())),
new ObjectEncoder(1024),
this.EXECUTION_UP_HANDLER,
this.EXECUTION_DOWN_HANDLER,
new UDPServerHandler());
return pipeline;
4.2. UDPServerHandler
void messageReceived(ChannelHandlerContext ctx, MessageEvent e)方法中
Plan plan = (Plan) e.getMessage();
LOGGER.info(plan);
plan.setStatus(" server received");
e.getChannel().write(plan,e.getRemoteAddress());
4.3. UDPClient
Bean发送方法:
Plan plan = new Plan();
plan.setAuthor("linfenliang");
plan.setContent("something about sequence");
plan.setDate("2012-11-07");
plan.setStatus("client send ");
initChannel();
channel.write(plan);