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完整的消息对象.

时间: 2025-01-06 02:06:28

netty 学习记录二的相关文章

Windows API 编程学习记录&lt;二&gt;

恩,开始写Windows API编程第二节吧. 上次介绍了几个关于Windows API编程最基本的概念,但是如果只是看这些概念,估计还是对Windows API不是很了解.这节我们就使用Windows API 让大家来了解下Windows API的用法. 第一个介绍的Windows API 当然是最经典的MessageBox,这个API 的作用就是在电脑上显示一个对话框,我们先来看看这个API的定义吧: int WINAPI MessageBox(HWND hWnd, LPCTSTR lpTe

Spring Boot学习记录(二)--thymeleaf模板

Spring Boot学习记录(二)–thymeleaf模板 标签(空格分隔): spring-boot 自从来公司后都没用过jsp当界面渲染了,因为前后端分离不是很好,反而模板引擎用的比较多,thymeleaf最大的优势后缀为html,就是只需要浏览器就可以展现页面了,还有就是thymeleaf可以很好的和spring集成.下面开始学习. 1.引入依赖 maven中直接引入 <dependency> <groupId>org.springframework.boot</gr

netty 学习记录一

最近在学习netty相关知识,觉得<netty 权威指南>这本书还是挺好的,适合我这种初学者.加上netty本身自带的许多例子,学起来还是挺有兴趣的.简单记录下, 一般服务器代码如下: public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerB

Netty学习记录

一.Netty简介 Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性. Netty 是一个 NIO client-server(客户端服务器)框架,使用 Netty 可以快速开发网络应用,例如服务器和客户 端协议. Netty 提供了一种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性. Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API

Mybatis学习记录(二)--Mybatis开发DAO方式

mybatis开发dao的方法通常用两种,一种是传统DAO的方法,一种是基于mapper代理的方法,下面学习这两种开发模式. 写dao之前应该要对SqlSession有一个更加细致的了解 一.mybatis的SqlSession使用范围 SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产

Spring学习记录(二)---容器和属性配置

下载spring包,在eclipse搭建spring环境. 这步我在eclipse中无法导入包,看网上的: http://sishuok.(和谐)com/forum/blogPost/list/2428.html 建一个java project 三个java文件,一个xml文件 1 package com.guigu.spring.beans; 2 3 public class HelloWord { 4 private String name; 5 public String getName(

Tornado学习记录二

Coroutines Coroutines are the recommended way to write asynchronous code in Tornado. Coroutines use the Python yield keyword to suspend and resume execution instead of a chain of callbacks (cooperative lightweight threads as seen in frameworks like g

netty学习(二)--传统的bio编程

网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息( 绑定ip地址和监听端口),客户端通过连接操作向服务端监听的地址发送连接请求,通过三次握手建立连接, 如果连接成功,双方就可以通过socket进行通信. 在基于传统的同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口:Socket负责发起连接请求 操作.操作连接成功后,双方通过输入和输出流进行同步阻塞通信. 下面是经典的时间服务器代码,分析工作过程: TimeSer

python学习记录二

一.列表(习惯了OC,总想把它叫成数组): names = ["ZhangYang","GuYun","XiangPeng","CuLiangChen"] names.append("LeiHaiDong")#添加names.insert(1,"ChenRongHua")#插入names[2] = "XieDi"#修改#删除names.remove("Che