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;
}
@Override
protected void initChannel(Channel ch) throws Exception {
// TODO Auto-generated method stub
SSLEngine 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 ;
@Override
protected void initChannel(Channel ch) throws Exception {
// TODO Auto-generated method stub
if (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;
}
@Override
protected 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>{
@Override
protected void initChannel(Channel ch) throws Exception {
// TODO Auto-generated method stub
ch.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>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
// TODO Auto-generated method stub
// handler text data 。
}
}
private class BinaryFrameHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame>{
@Override
protected 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{
@Override
protected 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));
@Override
public 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{
@Override
protected 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>{
@Override
protected 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。
}
}
}