netty 学习记录二

netty 最新版本是netty-5.0.0.Alpha1,去年10月份发布的,至今没有发新版本,估计这个版本还是比较稳定. 整包下载,里面包含一个 netty-example-5.0.0.Alpha1-sources.jar文件,提供了比较丰富的example例子,多看几遍还是非常有收获的,这里记录下.

先来看下channelHandler的两个不同继承:

方式一:直接从ChannelHandlerAdapter类里继承,读取操作从channelRead方法里执行

@Sharable
public class EchoServerHandler extends ChannelHandlerAdapter {

    private static final Logger logger = Logger.getLogger(
            EchoServerHandler.class.getName());

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.write(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);
        ctx.close();
    }
}

方式二:继承至SimpleChannelInboundHandler类,读取操作从方法messageReceived()里执行

public class FactorialServerHandler extends
		SimpleChannelInboundHandler<BigInteger> {

	private static final Logger logger = Logger
			.getLogger(FactorialServerHandler.class.getName());

	private BigInteger lastMultiplier = new BigInteger("1");
	private BigInteger factorial = new BigInteger("1");

	@Override
	public void messageReceived(ChannelHandlerContext ctx, BigInteger msg)
			throws Exception {
		// Calculate the cumulative factorial and send it to the client.
		System.out.println("server msg:" + msg);
		lastMultiplier = msg;
		factorial = factorial.multiply(msg);
		ctx.writeAndFlush(factorial);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		Formatter fmt = new Formatter();
		logger.info(fmt.format("Factorial of %,d is: %,d", lastMultiplier,
				factorial).toString());
		fmt.close();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		logger.log(Level.WARNING, "Unexpected exception from downstream.",
				cause);
		ctx.close();
	}
}

区别可以从SimpleChannelInboundHandler类的说明文字看出,  

SimpleChannelInboundHandler : ChannelHandler which allows to explicit only handle a specific type of messages. 也就是可以操作指定类型的信息.


接着看下 io.netty.example.factorial  这个包, 内容主要描述客户端向服务端发数字,服务端返回数字的阶乘给客户端,业务比较简单.

编解码操作涉及到的类,BigIntegerDecoder与NumberEncoder都是自定义的

pipeline.addLast("decoder", new BigIntegerDecoder());
pipeline.addLast("encoder", new NumberEncoder());

客户端有这么一段代码:

ChannelFuture future = null;
		for (int i = 0; i < 4096 && next <= count; i++) {
			future = ctx.write(Integer.valueOf(next));
			next++;
		}
		if (next <= count) {
			assert future != null;
			future.addListener(numberSender);
		}
		ctx.flush();

服务端代码:

@Override
	public void messageReceived(ChannelHandlerContext ctx, BigInteger msg)
			throws Exception {
		// Calculate the cumulative factorial and send it to the client.
		System.out.println("server msg:" + msg);
		lastMultiplier = msg;
		factorial = factorial.multiply(msg);
		ctx.writeAndFlush(factorial);
	}

看了客户端代码觉得代码在最后才flush的,所以服务端应该只收到一条消息,messageReceived方法应该只调用一次,结果是messageReceived方法调用次数与客户端发送次数一致. 有点奇怪. 看了下BigIntegerDecoder解码类操作才发现服务端的确只收到了一条消息,但是解码器解码成了多个对象(BigIntegerDecoder 类的decode方法被其父类ByteToMessageDecoder的callDecode方法反复读取同一条消息的ByteBuf,直到读完.),最后多次调用messageReceived方法.

以后如果自己写编解码类完全可以参考BigIntegerDecoder与NumberEncoder这两个类来.


最后来看下http的几个ChannelHandler

服务端:

 pipeline.addLast("decoder", new HttpRequestDecoder());
 pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
 pipeline.addLast("encoder", new HttpResponseEncoder());
 pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());

客户端:

p.addLast("codec", new HttpClientCodec());
p.addLast("aggregator", new HttpObjectAggregator(1048576));

刚看到时候觉得奇怪怎么服务端与客户端编解码方式不一样, 看下httpClientCoder类的说明(A combination of HttpRequestEncoder and HttpResponseDecoder which enables easier client side HTTP implementation),自然就懂了.

HttpObjectAggregator 了解这个handler先看段代码:

@Override
    protected void messageReceived(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof HttpRequest) {
           
        }

        if (msg instanceof HttpContent) {
           
        }
    }

一般http请求或者响应,解码器都将其解码成为多个消息对象,主要是httpRequest/httpResponse, httpcontent, lastHttpContent.然后反复调用messageReceive这个方法,

HttpObjectAggregator 这个handler就是将同一个http请求或响应的多个消息对象变成一个 fullHttpRequest完整的消息对象.





netty 学习记录二

上一篇:JsonPath的使用


下一篇:006.ASP.NET MVC ActionResults说明