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

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。
}

}

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值