Netty(2)-服务端与客户端的启动流程

一.服务端启动流程分析

1.四大必须属性

从一个最简单的服务端Demo看起

  • NIOServer
public class NIOServer {
    public static void main(String[] args) {
        ServerBootstrap serverBootstrap = new ServerBootstrap(); // 启动引导器
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(); // 监听组
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(); // 工作组

        serverBootstrap.group(bossGroup, workerGroup)  // 指定线程模型:监听组和工作组
                .channel(NioServerSocketChannel.class) // IO模型:NIO模式
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    // 初始化channel:连接后的读写逻辑
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                System.out.println(String.format("服务端接收到消息:%s", msg));
                            }
                        });
                    }
                }).bind(8000);  //启动端口
    }
}

要启动Netty服务端,必须要指定四类必须属性,分别是:

  1. 线程模型
  2. IO模型
  3. 连接后的读写逻辑
  4. 启动端口

在这里插入图片描述

2.启动引导器:serverBootstrap

所有的服务都在启动器上进行注册和配置。

3.线程模型:bossGroup和workerGroup

创建了两个NioEventLoopGroup,这两个对象可以看做是传统IO编程模型的两大线程组,bossGroup表示监听端口,accept 新连接的线程组,workerGroup表示处理每一条连接的数据读写的线程组。bossGroup接收完连接,会交给workerGroup去处理。最后通过.group(bossGroup, workerGroup)去指定线程模型。

4.IO模型:NioServerSocketChannel和OioServerSocketChannel

通过.channel(NioServerSocketChannel.class)来指定 IO 模型,当然,这里也有其他的选择,如果你想指定 IO 模型为 BIO,那么这里配置上OioServerSocketChannel.class类型即可,通常不会指定BIO为线程模型,因为Netty的优势就在于NIO。

5.连接后读写逻辑

.childHandler()方法,给这个引导类创建一个ChannelInitializer,这里主要就是定义后续每条连接的数据读写,业务处理逻辑。也可新创建一个类并继承ChannelInboundHandlerAdapter来实现读写逻辑。

6.引导器其他方法参数

  • childHandler():给引导类创建ChannelInitializer定义后续每条连接的数据读写,业务处理逻辑,泛型参数NioSocketChannel是Netty对NIO类型的连接的抽象,而NioServerSocketChannel也是对NIO类型的连接的抽象

  • bind():异步地返回ChannelFuture,给ChannelFuture添加监听器GenericFutureListener,在GenericFutureListener的operationComplete方法里面监听端口是否绑定成功

  • childHandler():用于指定处理新连接数据的读写处理逻辑,handler()用于指定在服务端启动过程中的一些逻辑

  • attr():给服务端的channel即NioServerSocketChannel指定一些自定义属性,通过channel.attr()取出该属性,给NioServerSocketChannel维护一个map

  • childAttr():给每一条连接指定自定义属性,通过channel.attr()取出该属性

  • childOption():给每条连接设置一些TCP底层相关的属性:

       ChannelOption.SO_KEEPALIVE表示是否开启TCP底层心跳机制,true为开启
       ChannelOption.SO_REUSEADDR表示端口释放后立即就可以被再次使用,因为一般来说,一个端口释放后会等待两分钟之后才能再被使用
       ChannelOption.TCP_NODELAY表示是否开始Nagle算法,true表示关闭,false表示开启,通俗地说,如果要求高实时性,有数据发送时就马上发送,就关闭,如果需要减少发送次数减少网络交互就开启
    
  • option():给服务端channel设置一些TCP底层相关的属性:

       ChannelOption.SO_BACKLOG表示系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁,服务器处理创建新连接较慢,适当调大该参数
    

二.客户端启动流程分析

从一个最简单的Netty客户端Demo看起

  • NIOClient
public class NIOClient {
    public static void main(String[] args) throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap(); // 引导启动类
        NioEventLoopGroup group = new NioEventLoopGroup(); // 工作组

        bootstrap
        .group(group) // 添加线程模型
        .channel(NioSocketChannel.class) // 添加IO模型
        .handler(new ChannelInitializer<SocketChannel>() {// 添加连接后的读写逻辑
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new StringEncoder());
            }
        });

        Channel channel = bootstrap.connect("127.0.0.1", 8000).channel(); // 建立连接
        while (true) {
            String message = String.format("HelloWorld From %s", new SimpleDateFormat("hh:mm:ss").format(new Date()));
            // 通过连接向服务端发送消息
            channel.writeAndFlush(message);
            Thread.sleep(2000);
        }
    }
}

对于客户端的启动来说,和服务端的启动类似,依然需要线程模型、IO 模型,以及连接后业务处理逻辑和连接主机与端口,这4大参数,启动流程如下:
在这里插入图片描述

其他方法与服务端类似

发布了309 篇原创文章 · 获赞 205 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/104159817