Netty实战读书笔记(第十一章(上))

来源:互联网 发布:醉虾 知乎 编辑:程序博客网 时间:2024/05/17 09:36

Netty提供的预制的Handler和编解码器。

Netty通过预制的SslHandler保证数据在pipeline中加密和解密,SslHandler在其他Handler的逻辑处理后才能进行加密。


import javax.net.ssl.SSLEngine;import io.netty.channel.Channel;import io.netty.channel.ChannelInitializer;import io.netty.handler.ssl.SslContext;import io.netty.handler.ssl.SslHandler;public class SslChannelInitializer extends ChannelInitializer<Channel>{private final SslContext context;private final boolean startTsl;public SslChannelInitializer(SslContext context , boolean startTsl){this.context = context;this.startTsl = startTsl;}@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stubSSLEngine engine = context.newEngine(ch.alloc());// 将channel的ch.pipeline().addFirst(new SslHandler(engine , startTsl));// sslHandler一般为pipeline的第一个handler,这样保证数据入站时 解密,出站最后加密。}}
Netty提供了Http、Https的应用:

import io.netty.channel.Channel;import io.netty.channel.ChannelInitializer;import io.netty.handler.codec.http.HttpRequestDecoder;import io.netty.handler.codec.http.HttpRequestEncoder;import io.netty.handler.codec.http.HttpResponseDecoder;import io.netty.handler.codec.http.HttpResponseEncoder;public class HttpPipelineInitializer extends ChannelInitializer<Channel> {private boolean client ;@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stubif (client){ch.pipeline().addLast(new HttpRequestEncoder());// 客户端对于发送的编码。ch.pipeline().addLast(new HttpResponseDecoder());//客户端对于受到的消息解码。} else {ch.pipeline().addLast(new HttpResponseEncoder());// 服务器对于response编码ch.pipeline().addLast(new HttpRequestDecoder());// 客户端对于client的request解码。}}}
在http请求中由于http可能有不同的部分组成,所以需要聚合不同的部分形成httpObject。
import io.netty.channel.Channel;import io.netty.channel.ChannelInitializer;import io.netty.handler.codec.http.HttpClientCodec;import io.netty.handler.codec.http.HttpServerCodec;/** * http自动聚合,将httpObject的不同部分聚合为一个HttpObject。 * @author pc * */public class HttpAggregationInitializer extends ChannelInitializer<Channel>{private boolean isClient;public HttpAggregationInitializer(boolean isClient){this.isClient = isClient;}@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stub// 如果是客户端,则添加HttpClientCodec().if (isClient){ch.pipeline().addLast("client" , new HttpClientCodec());} else {ch.pipeline().addLast("server" , new HttpServerCodec());}}}

Http压缩数据,在Netty中也提供了channelHandler用于数据压缩,webSocket。

import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInitializer;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.HttpClientCodec;import io.netty.handler.codec.http.HttpObjectAggregator;import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;import io.netty.handler.ssl.SslHandler;/** * webSocket 在一个单个的TCP连接上提供全双工的通信协议,代替http轮询请求的方式。 * @author pc * */public class WebSocketServerInitializer extends ChannelInitializer<Channel>{@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stubch.pipeline().addLast(new SslHandler(null) , new HttpClientCodec() , // 提供最大为128kB的消息object。new HttpObjectAggregator(128 * 1024),// 如果请求以/webSocket 开头,则升级为websocket。new WebSocketServerProtocolHandler("/webSocket"), // 处理文本数据。new TextFrameHandler() , // 处理二进制数据。new BinaryFrameHandler());}private class TextFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {// TODO Auto-generated method stub// handler text data 。}}private class BinaryFrameHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame>{@Overrideprotected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame msg) throws Exception {// TODO Auto-generated method stub// handler binary data 。}}}
检测空闲连接与超时,能够最大限度的使用资源。

Netty的主要提供了几种用于检测超时与空闲连接的ChannelHandler的实现,主要有IdleStateHandler、ReadTimeOutHandler、WriteTimeOutHandler。

import java.util.concurrent.TimeUnit;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.Channel;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import io.netty.channel.ChannelInitializer;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.timeout.IdleStateEvent;import io.netty.handler.timeout.IdleStateHandler;import io.netty.util.CharsetUtil;/** * IdleStateHandler实现。 * @author pc * */public class IdleStateHandlerInitializer extends ChannelInitializer{@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stub// IdleStateHandler发送心跳,在发送心跳之后60秒没有收到反馈则触发IdleEventState事件,通过重写userEventTriggered方法处理。ch.pipeline().addLast(new IdleStateHandler(0, 0, 60, TimeUnit.MILLISECONDS) , new HeartBeatHandler());}private static class HeartBeatHandler extends ChannelInboundHandlerAdapter{//发送到远程节点的心跳消息        private static final ByteBuf HEARTBEAT_SEQUENCE =                Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(                "HEARTBEAT", CharsetUtil.ISO_8859_1));@Overridepublic void userEventTriggered(ChannelHandlerContext ctx,            Object evt) throws Exception {// 如果事件为IdleStateEvent事件,则。。。if (evt instanceof IdleStateEvent){ChannelFuture future = ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);// 如果不是,则将它传给下一个ChannelHandler。} else {super.userEventTriggered(ctx, evt);}}}}

不同的协议帧的划分方法不同,一般分为按照分隔符划分、长度划分。

SMTP、POP3、IMAP按照分隔符划分帧,netty提供了handler分割符划分帧的类。


import io.netty.buffer.ByteBuf;import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInitializer;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.LineBasedFrameDecoder;/** *  * @author pc *RPC协议文本中有许多协议都是通过分割符定义不同的帧,比如(SMTP、POP3、IMAP)。 */public class LineBasedHandlerInitializer extends ChannelInitializer{@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stub// 一些协议按照分割符编码字节流,LineBasedFrameDecoder将字节流按照分隔符分割为帧,将帧传入下一个handler。ch.pipeline().addLast(new LineBasedFrameDecoder(64 * 1024) , new FrameHandler());}private class FrameHandler extends SimpleChannelInboundHandler<ByteBuf>{@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {// TODO Auto-generated method stub// do something handler。}}}
RFC定义部分协议使用长度区分帧。


import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
/**
 * 
 * @author pc
 * 基于长度的协议分帧。
 */
public class LengthBaseFrameInitializer extends ChannelInitializer{


@Override
protected void initChannel(Channel ch) throws Exception {
// TODO Auto-generated method stub

ChannelPipeline pipeline = ch.pipeline();
// 最大 的长度,开始的偏移量,没帧的长度。
pipeline.addLast(new LengthFieldBasedFrameDecoder(64 * 1024, 0, 8), 
new LengthHandler());
}
private class LengthHandler extends SimpleChannelInboundHandler<ByteBuf>{


@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
// TODO Auto-generated method stub
// do some handler。
}

}

}



原创粉丝点击