netty4学习入门2-channel的回调和执行流程分析

针对之前写的netty作为http服务器的helloworld程序(https://blog.csdn.net/hami700100332/article/details/80357311)我们进一步改进TestHttpHandler

package com.baidu.netty.firstExample;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

import java.net.URI;

public class TestHttpHandler extends SimpleChannelInboundHandler {

    /**
     * 该方法在5.0中被命名为messageReceived,估计后期还是会对该方法进行重命名
     * 该方法的主要作用是读取客户端的请求,并生产相应数据,我们在该处返回一个helloworld
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
            if (msg instanceof HttpRequest) //过滤非HTTP的请求和垃圾请求
            {
                HttpRequest req = (HttpRequest)msg; //将对象强制类型转换为HttpRequest的对象
                URI uri = new URI(req.uri()); //注意不要引错了包,是java.net下的
                if ("/favicon.ico".equals(uri.getPath())) //过滤掉图标请求
                {
                    System.out.println("get favicon.icon");
                    return;
                }
                System.out.println("invoked....");
                //1.定义返回对象
                ByteBuf content = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8);
                //2. 定义response返回对象,注意该处的response对象不是servlet中的HttpResponse,他是netty自己封装的返回数据,跟http没有任何关系
                FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK, content);
                //3. 设置返回的数据头信息
                response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
                //4. 调用ctx返回response对象
                ctx.writeAndFlush(response);
            }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel added");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel registered");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel active");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel ininactive");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel unregistered");
    }
}

然后使用curl进行访问:

netty4学习入门2-channel的回调和执行流程分析_第1张图片

从结果上看,我们发现netty的channel的执行流程如下:

1. 客户端连上netty服务器后,马上调用handlerAdded方法完成channel的添加操作(所谓channel可以理解为一个客户端)

2. 添加操作执行完成以后立马调用channelRegistered方法将channel注入到netty中管理起来

3. 注册好以后调用服务器端的channelActive方法,让其处于激活状态

4. 调用channelRead0方法完成客户端数据的读取和相应

5. 调用完成以后curl主动断开服务器的链接,并通知服务器端,服务器端就会调用channelInactive方法处理回调事件

6. 最后从netty的注册中将该channel删除掉

这就是netty执行回调的所有流程,特别注意的是该处我们使用的测试工具是crul,那么我们使用浏览器再次测试,会发现结果有所不同:

netty4学习入门2-channel的回调和执行流程分析_第2张图片

所谓的不同不是指顺序这个顺序是多线程控制,不能作为依据,所谓的不同指的是该处没有

channel ininactive

channel unregistered

如果你真的按照笔记去做测试,那么还会出现一个有意思的事情,就是过了一段时间以后他们又出来了或者你不凑巧关了浏览器他也打印出来了。

那么是为什么呢?

crul作为一个命令行工具他发送一个命令然后得到结果以后就会自己主动的关闭连接,

而浏览器作为一个http请求的发送者他不会自己主动的关闭连接,如果浏览器使用的http1.0的协议,那么当服务器端响应完成以后就会由服务器端主动关闭连接,如果浏览器使用的是http1.1,那么他就会出现我们该处出现的情况,究其原因是因为1.1的协议是支持keepalived的,alived的时间会有一个默认值当然也可以自己去设置,那么服务器处理完该请求以后会默认等待keepalived的时间,如果过了这个时间还没有请求过来,那么会由服务器主动断开该连接,而自己关闭浏览器属于客户端自己关闭连接,他会通知服务器,也会调用对应的时间

总结:

该例子主要学习netty的事件和事件处理流程,对以后的心跳检测、广播、消息推送等有非常重要的意义,同时也是学习netty必须要牢牢掌握的知识点。

你可能感兴趣的:(netty自学笔记)