手把手构建Netty

1.Netty基础

Netty是一个提供了易于使用的API的客户端、服务器框架;
并发高-NIO(非阻塞IO)
传输快-零拷贝:
分析:
使用了NIO的零拷贝;java中内存是分为堆和栈,还有字符串常量池等等;
如果有一些数据需要从IO中读取,并且放到堆里面;中间会经历一些缓冲区;也就是说,读的过程会分为两个步骤:从IO流中读取出来,放到缓存区;缓冲区读取放到堆里面;
当它需要去接受数据或者是传输数据。会去开辟一个新的堆内存;然后数据直接从IO读取到新的堆内存中去

对于协议的支持如下;
在这里插入图片描述
BIO:同步阻塞IO

Server会有一个专门的线程acceptor;专门来监听客户端之间的请求;
客户端增多的时候,就会频繁的创建和销毁相应线程,就要考虑线程池;

NIO:同步非阻塞IO

BIO、NIO与AIO的区别与理解:
三者的区别详细可参考如下链接:
https://blog.csdn.net/TOMORROW6COME/article/details/140048654

使用NIO所遇到的问题:
类库;api相对较为复杂;需要具备java多线程的技能;
断线重连,网络阻塞等问题的处理方式,实现难度较大;NIO内置使用存在一些bug;

Netty优点:高效;简单;支持主流协议;可定制性强;性能高;
Dubbo使用的是Netty;

2.Netty三种线程模型

Reactor线程模型;
在这里插入图片描述
只能用于小型的应用场景;
不适用于高负载高并发场景;因为一个NIO线程要去同时处理成百上千的请求;
性能支撑不了;即便给予服务器负载;对于海量的消息处理,编解码,处理跟发送消息
无法满足;超时,然后不断轮训;会造成恶性循环;

在这里插入图片描述
主从线程模型:一组线程池接受请求;一组线程池处理IO
在这里插入图片描述

3.Netty快速入门

(1)构建Netty的聊天服务器
使用主从线程池构建聊天服务器:
在这里插入图片描述
在启动的时候会返回一个实例;为ChannelFuture;
他的解释如下:大概意思就是因为NIO;所以会立即返回一个结果;同时,可能没有信息;
所以使用ChannelFuture,替代作为一个结果返回;
在这里插入图片描述

public static void main(String[] args) throws Exception {
    // 构建主从线程池
    // 定义主线程池,用于接受客户端的连接;但是不做任何处理,比如老板会谈业务,拿到业务就会交给workerGroup进行处理
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    // 定义从线程池,处理主线程池交代的任务;公司业务员开展业务,完成老板交代的任务
    EventLoopGroup workerGroup = new NioEventLoopGroup();

    try {
        // 构建Netty服务器
        ServerBootstrap server = new ServerBootstrap();         // 服务启动类;
        server.group(bossGroup,workerGroup)                     // 把主从线程池组放入到启动类中
                .channel(NioServerSocketChannel.class)          // 设置NIO双向通道
                .childHandler(null);                            // 设置处理器,用于处理workerGroup业务
        // 启动server,并且绑定端口号875,同时启动方式为同步
        ChannelFuture channelFuture = server.bind(875).sync();   //.sync是保证服务启动后一直运行;不写sync,代码一运行完就没有了

        //监听关闭的channel
        channelFuture.channel().closeFuture().sync();
    } finally {
        // 优雅关闭线程池组
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

(2)设定channel的初始化器
Pipeline需要开发者自己去编写;handler助手类:用于处理请求;
在这里插入图片描述

/**
 * Created by nly
 *
 * 初始化器,channel注册后,会执行里面的响应的初始化方法
 **/
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        // 通过SocketChannel 获得对应的管道
        ChannelPipeline pipeline = channel.pipeline();

        /**
         * 通过管道,添加handler处理器
         */

        // HttpServerCodec 是netty 自己提供的助手类,此处可以理解为管道中的拦截器
        // 当请求到服务端,我们需要进行做解码,相应到客户端做解码
        pipeline.addLast("",new HttpServerCodec());

        // 添加自定哦助手类,当请求访问,返回"hello,netty"
        pipeline.addLast("",null);

    }
}

(3)编写HTTP自定义助手类
先处理http;先不构建Netty服务器;
HttpObject是处理的泛型;
先构建基本的逻辑与框架;
通过上下文对象ctx去获取channel;拿到channel之后,就能获取到跟客户端
相关的信息了
概念缓冲区:bytebuf:定义数据发送的消息;读写数据;

/**
 * 创建自定义助手类
 *
 **/
public class HttpHandler extends SimpleChannelInboundHandler<HttpObject> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx,
                                HttpObject msg) throws Exception {
        // 获取channel
        Channel channel = ctx.channel();

        // 打印客户端的远程地址
        System.out.println(channel.remoteAddress());

        // 通过缓冲区定义发送的消息,读写数据都是通过缓冲区进行数据交换的
        ByteBuf content = Unpooled.copiedBuffer("hello netty!", CharsetUtil.UTF_8);

        // 构建http的response
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK,
                content);
        // 为响应添加数据类型和数据长度
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());

        // 把响应数据写到缓冲区再刷到客户端
        ctx.writeAndFlush(response);
    }
}

(3)Netty服务的生命周期
关注到netty的生命周期问题;
ChannelInboundHandlerAdapter
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值