Netty 提供了ChannelHandler接口,还有用于Codes的ChannelHandler子接口。通过组合搭配, 灵活的构建我们需要的应用。
SSL / TSL 服务
搭建SSL/TSL,Java EE 规范提供了 SSLContext 跟 SSLEngine接口,加之Netty为我们实现了一个SSLHandler,可以容易的实现。
其过程:
示例代码:
public class SslChannelInitializer extends ChannelInitializer<Channel> { private final SSLContext context; private final boolean client; private final boolean startTls; public SslChannelInitializer( SSLContext context, boolean client, boolean startTls ) { this.context = context; this.client = client; this.startTls = startTls; } @Override protected void initChannel( Channel ch ) throws Exception { SSLEngine engine = context.createSSLEngine(); engine.setUseClientMode( client ); ch.pipeline().addFirst( "ssl" , new SslHandler(engine, startTls)); } }
Http 服务
实现支持Http服务,需要几个Codes
HttpRequestEncoder、HttpResponseEncoder、HttpRequestDecoder、HttpResponseDecoder
示例代码:
public class HttpDecoderEncoderInitializer extends ChannelInitializer<Channel> { private final boolean client; public HttpDecoderEncoderInitializer( boolean client ) { this.client = client; } @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline channelPipeline = ch.pipeline(); if ( client ) { channelPipeline.addLast( "decoder", new HttpResponseDecoder() ); channelPipeline.addLast( "encoder", new HttpRequestEncoder() ); //or //channelPipeline.addLast( "codes", new HttpServerCodec() ); } else { channelPipeline.addLast( "decoder", new HttpRequestDecoder() ); channelPipeline.addLast( "encoder", new HttpRequestEncoder() ); //or //channelPipeline.addLast( "codes", new HttpClientCodec() ); } } }对于分段的Http信息,使用HttpObjectAggregator
public class HttpAggregatorInitializer extends ChannelInitializer<Channel> { private final boolean client; public HttpAggregatorInitializer( boolean client ) { this.client = client; } @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline channelPipeline = ch.pipeline(); if ( client ) { channelPipeline.addLast( "codes", new HttpClientCodec() ); } else { channelPipeline.addLast( "codes", new HttpServerCodec() ); } /* * if message is getting bigger , raise a TooLongFrameException is thrown */ channelPipeline.addLast( "aggegator", new HttpObjectAggregator( 1024 * 512 ) ); } }对于压缩的数据。
public class HttpCompressionInitializer extends ChannelInitializer<Channel> { private final boolean client; public HttpCompressionInitializer( boolean client ) { this.client = client; } @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if ( client ) { pipeline.addLast( "codes", new HttpClientCodec() ); pipeline.addLast( "decompressor", new HttpContentDecompressor() ); } else { pipeline.addLast( "codes", new HttpServerCodec() ); pipeline.addLast( "compressor", new HttpContentCompressor() ); } } }
Https 服务。
public class HttpsCodecInitializer extends ChannelInitializer<Channel> { private final SSLContext context; private final boolean client; public HttpsCodecInitializer( SSLContext context, boolean client ) { this.context = context; this.client = client; } @Override protected void initChannel( Channel ch ) throws Exception { SSLEngine engine = context.createSSLEngine(); engine.setUseClientMode( client ); ChannelPipeline pipeline = ch.pipeline(); pipeline.addFirst( "ssl", new SslHandler( engine ) ); if ( client ) { pipeline.addLast( "codes", new HttpClientCodec() ); } else { pipeline.addLast( "codes", new HttpServerCodec() ); } } }
处理心跳跟连接超时
IdleStateHandler : 当连接空闲状态到达超时时间,触发事件,且事件源为IdleStateEvent
ReadTimeoutHandler : 读数据超时,抛出ReadTimeoutException
WriteTimeoutHandler :写数据超时,抛出WriteTimeoutException
例子代码:
public class IdleStateHandlerInitializer extends ChannelInitializer<Channel> { @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline channelPipeline = ch.pipeline(); channelPipeline.addLast( new IdleStateHandler( 0, 0, 60, TimeUnit.SECONDS ) ); channelPipeline.addLast( new HeadbeatHandler() ); } private static final class HeadbeatHandler extends ChannelInboundHandlerAdapter { private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer( Unpooled.copiedBuffer( "HEARTBEAT", CharsetUtil.ISO_8859_1 ) ); @Override public void userEventTriggered( ChannelHandlerContext ctx, Object evt ) throws Exception { if ( evt instanceof IdleStateEvent ) { ctx.writeAndFlush( HEARTBEAT_SEQUENCE.duplicate() )// .addListener( ChannelFutureListener.CLOSE_ON_FAILURE ); } else { super.userEventTriggered( ctx, evt ); } } } }
关于定界符的协议
DelimiterBasedFameDecoder : 根据定界符抽取数据片段的解码器
LineBasedFrameDecoder:基于行片段的解码器,用于\r\n定界符分行。
public class LineBasedHandlerInitializer extends ChannelInitializer<Channel> { @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline channelPipeline = ch.pipeline(); channelPipeline.addLast( new LineBasedFrameDecoder( 65 * 1024 ) ); channelPipeline.addLast( new FrameHandler()); } private static final class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override protected void channelRead0( ChannelHandlerContext ctx, ByteBuf msg ) throws Exception { // do something } } }扩展例子:
public class CmdHandlerInitializer extends ChannelInitializer<Channel> { private static class Cmd { private final ByteBuf name; private final ByteBuf args; public Cmd( ByteBuf name, ByteBuf args ) { this.name = name; this.args = args; } } private static class ComDecoder extends LineBasedFrameDecoder { public ComDecoder( int maxLength ) { super( maxLength ); } @Override protected Object decode( ChannelHandlerContext ctx, ByteBuf buffer ) throws Exception { ByteBuf frame = (ByteBuf) super.decode( ctx, buffer ); if ( frame == null ) { return null; } int index = frame.indexOf( frame.readerIndex(), frame.writerIndex(), (byte) ' ' ); return new Cmd( frame.slice( frame.readerIndex(), index ), frame.slice( index + 1, frame.writerIndex() ) ); } } public static class CmdHandler extends SimpleChannelInboundHandler<Cmd> { @Override protected void channelRead0( ChannelHandlerContext ctx, Cmd msg ) throws Exception { // do something } } @Override protected void initChannel( Channel ch ) throws Exception { ch.pipeline().addLast( new ComDecoder( 65 * 1024 ) ); ch.pipeline().addLast( new CmdHandler() ); } }
关于约定长度的协议处理
FixedLengthFrameDecoder : 抽取固定的字节长度,形成一个Frame
LengthFieldBasedFrameDecoder : 抽取信息头设置长度,划分为不同的Frame
public class LengthBasedInitializer extends ChannelInitializer<Channel> { @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline channelPipeline = ch.pipeline(); channelPipeline.addLast( new LengthFieldBasedFrameDecoder(65*1024, 0, 8)); channelPipeline.addLast( new FrameHandler()); } private static class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override protected void channelRead0( ChannelHandlerContext ctx, ByteBuf msg ) throws Exception { // todo something } } }
写大数据
Netty允许写数据,使用 zero-memory-zero 方式。 对javaAPI进行的封装,处理了很多细节。
提供了一个分块处理的ChunkedWriterHandler
public class ChunkedWriteHandlerInitializer extends ChannelInitializer<Channel> { private final File file; public ChunkedWriteHandlerInitializer( File file ) { this.file = file; } @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline channelPipeline = ch.pipeline(); channelPipeline.addLast( new ChunkedWriteHandler() ); channelPipeline.addLast( new WriteStreamHandler() ); } private class WriteStreamHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive( ChannelHandlerContext ctx ) throws Exception { super.channelActive( ctx ); ctx.writeAndFlush( new ChunkedStream( new FileInputStream( ChunkedWriteHandlerInitializer.this.file ) ) ); } } }传java对象序列化数据
使用JDK序列化,Netty提供了
CompatibleObjectDecoder、CompatibleObjectEncoder、
CompactObjectDecoder、CompactObjectEncoder
使用Jboss的Marshalling, Netty提供了
CompatibleMarshallingDecoder、CompatibleMarshallingEncoder
MarshallingDecoder、MarshallingEncoder
public class MarshallingInitializer extends ChannelInitializer<Channel> { private final MarshallerProvider marshallerProvider; private final UnmarshallerProvider unmarshallerProvider; public MarshallingInitializer( MarshallerProvider marshallerProvider, UnmarshallerProvider unmarshallerProvider ) { this.marshallerProvider = marshallerProvider; this.unmarshallerProvider = unmarshallerProvider; } @Override protected void initChannel( Channel ch ) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast( new MarshallingDecoder( unmarshallerProvider ) ); pipeline.addLast( new MarshallingEncoder( marshallerProvider ) ); pipeline.addLast( new ObjectHandler() ); } private static class ObjectHandler extends SimpleChannelInboundHandler<Serializable> { @Override protected void channelRead0( ChannelHandlerContext ctx, Serializable msg ) throws Exception { // do somethod } } }