欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Netty入门与实战——服务端源码及启动流程

程序员文章站 2022-04-23 11:52:51
...

此系列文章来源于总结归纳Netty 入门与实战:仿写微信 IM 即时通讯系统

代码:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;

public class NettyServer {

    private static final int BEGIN_PORT = 8000;

    public static void main(String[] args) {
        NioEventLoopGroup boosGroup = new NioEventLoopGroup();    //创建新连接
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();  //读取数据以及业务逻辑处理

        final ServerBootstrap serverBootstrap = new ServerBootstrap();   //引导类,进行服务端的启动工作
        final AttributeKey<Object> clientKey = AttributeKey.newInstance("clientKey");
        serverBootstrap
                .group(boosGroup, workerGroup)   //给引导类配置两大线程组(线程模型)
                .channel(NioServerSocketChannel.class)   //指定IO模型为NIO
                .attr(AttributeKey.newInstance("serverName"), "nettyServer")  //给NioServerSocketChannel指定一些自定义属性,通过channel.attr()取出这个属性
                .childAttr(clientKey, "clientValue")  //给每一条连接指定自定义属性
                .option(ChannelOption.SO_BACKLOG, 1024)//表示系统用于临时存放已完成三次握手的请求的队列的最大长度
                .childOption(ChannelOption.SO_KEEPALIVE, true)//是否开启TCP底层心跳机制,true为开启
                .childOption(ChannelOption.TCP_NODELAY, true)//是否开启Nagle算法,true表示关闭,false表示开启,通俗地说,如果要求高实时性,有数据发送时就马上发送,就关闭,如果需要减少发送次数减少网络交互,就开启。
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) {
                        System.out.println(ch.attr(clientKey).get());
                    }
                });   //定义后续每条连接的数据读写,业务处理逻辑


        bind(serverBootstrap, BEGIN_PORT);   //递增绑定端口
    }

    private static void bind(final ServerBootstrap serverBootstrap, final int port) {
        serverBootstrap.bind(port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("端口[" + port + "]绑定成功!");
            } else {
                System.err.println("端口[" + port + "]绑定失败!");
                bind(serverBootstrap, port + 1);
            }
        });
    }
}

解析:

*首先创建了两个NioEventLoopGroup,这两个对象可以看做是传统IO编程模型的两大线程组,bossGroup表示监听端口,accept 新连接的线程组,workerGroup表示处理每一条连接的数据读写的线程组。类比为:一个工厂要运作,必然要有一个老板负责从外面接活,然后有很多员工,负责具体干活,老板就是bossGroup,员工们就是workerGroupbossGroup接收完连接,扔给workerGroup去处理。

*然后创建了一个引导类 ServerBootstrap的对象,这个类将引导我们进行服务端的启动工作

*通过.group(bossGroup, workerGroup)给引导类配置两大线程组,指定引导类的线程模型

*通过.channel(NioServerSocketChannel.class)来指定 IO 模型

*调用childHandler()方法,给这个引导类创建一个ChannelInitializer,定义后续每条连接的数据读写,业务处理逻辑

*ChannelInitializer这个类中,NioSocketChannel就是 Netty 对 NIO 类型的连接的抽象,前面NioServerSocketChannel也是对 NIO 类型的连接的抽象

*递增地绑定端口,起始端口号BEGIN_PORT=8000,若绑定失败则端口号+1,直到绑定端口成功

总结:

1、创建一个引导类,然后给他指定线程模型,IO模型,连接读写处理逻辑,绑定端口之后,服务端就启动起来了。

2、bind 方法是异步的,我们可以通过这个异步机制来实现端口递增绑定。

3、Netty 服务端启动额外的参数,主要包括给服务端 Channel 或者客户端 Channel 设置属性值,设置底层 TCP 参数。