Netty从入门到精通————实例(一)

学习netty先从最简单的实例开始,三个实体类大概是如下图
在这里插入图片描述
首先先创建TestServer实体类

package com.icss.po;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.sctp.nio.NioSctpServerChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class TestServer {
    public static  void  main(String[] args) throws  Exception{
        //事件线程组
        EventLoopGroup bossGroup =  new NioEventLoopGroup();
        EventLoopGroup workerGroup =  new NioEventLoopGroup();
        try{

            //服务端启动类
            ServerBootstrap serverBootstrap =  new ServerBootstrap();
            //启动服务器
            serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)//反射方式
                    .childHandler(new TestServerInitializer());
            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            //关闭监听
            channelFuture.channel().closeFuture().sync();
        }
        finally {
            //关闭
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();

        }

    }

}

然后创建TestServerInitializer实体类

package com.icss.po;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpServerCodec;

public class TestServerInitializer  extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline  = ch.pipeline();
        //HttpServerCodec是HttpRequestDecoder(请求客户端发向给服务端会做一个解码,解码操作是将请求信息提取出来)
        // 和HttpRequestEncoder(Http相应的编码服务端向客户端输出响应的时候做相应的编码工作)的组合

        pipeline.addLast( "httpServerCodec",new HttpServerCodec());
        pipeline.addLast("testHttpServerHandler",new TestHttpServerHandler());
    }
}

最后创建TestServerHandler实体类

package com.icss.po;

        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;


//SimpleChannelInboundHandler服务器对进来相应的处理
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        //得到类名
        System.out.println(msg.getClass());
        //获取远程连接
        System.out.println(ctx.channel().remoteAddress());
        if (msg instanceof  HttpRequest){
            //j进行强制类型转换
            HttpRequest httpRequest =  (HttpRequest)msg;
            System.out.println("请求方法名"+httpRequest.method().name());
            URI uri =  new URI(httpRequest.uri());
            if ("favicon.ico".equals(uri.getPath())){
                System.out.println("请求favicon.ico");
                return;
            }
            //1、读取客户端发过来的请求,并且向客户端返回相应的方法
            ByteBuf content = Unpooled.copiedBuffer("Hello world", CharsetUtil.UTF_8);//返回的内容
            //
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    HttpResponseStatus.OK,content);//指定http的协议,状态是200
            //设置http协议的头部信息,内容类型只返回字符串
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            //相应类型的长度
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH , content.readableBytes());
            //2、将相应返回给客户端
            // ctx. write()并不会返回给客户端,将信息放在缓冲区中
            ctx.writeAndFlush(response);
            //判断http是1.0还是1.1 紧着判断等到时间  最后进行关闭
            ctx.channel().closeFuture();
        }

    }

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

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

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

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

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

启动主程序
按住win+R 进入到命令窗口 输入命令telnet localhost 8899
如果显示Talent窗口则说明第一个实例而创建成功

浏览器访问地址http://localhost:8899/
打开调试模式的network或者网络可以看到有两个请求地址
在这里插入图片描述
在后台程序加上打印也确确实实请求了两次
在这里插入图片描述

在这里插入图片描述
如果用telnet去访问确是访问了一次
在这里插入图片描述
出现的原因时因为有些网站他们请求图标所以会请求两次
在这里插入图片描述
对于http协议来说基于请求和相应式无状态模式,而对于netty底层是ServerSocket不断进行死循环,对于应用层来说,当获取到客户端的请求之后,首先要对http请求进行判断是http1.1还是http1.0,如果是基于http1.1 有一个keep alive时间等待,这个时间一到,服务器自动的将客户端关闭掉,如果是http1.0 协议是一个短连接的协议请求发送之后,服务器就会把链接关闭掉。

猜你喜欢

转载自blog.csdn.net/ling_ling1997/article/details/89338034