Java教程

Netty网络通讯入门详解

本文主要是介绍Netty网络通讯入门详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
概述

Netty是一个高性能的异步事件驱动的网络应用程序框架,它简化了TCP/UDP协议编程。本文将详细介绍Netty网络通讯入门的相关知识,包括环境搭建、核心概念与组件以及实战案例。通过本文,读者可以全面了解并掌握Netty网络通讯入门的技巧和方法。

Netty简介及环境搭建

Netty是什么

Netty是一个高性能的异步事件驱动的网络应用程序框架,它基于NIO(Non-blocking I/O)设计。Netty简化了TCP/UDP协议编程,提供了灵活的事件驱动模型和高度优化的内存管理机制。使用Netty可以轻松地实现高性能的网络服务器和客户端程序,同时保持代码的可读性和可维护性。

Netty的优点

Netty拥有以下优点:

  • 高性能:Netty使用高效的内存管理和零拷贝技术,减少了资源消耗和延迟。
  • 异步非阻塞:Netty基于NIO设计,支持异步非阻塞调用模型,可以显著提高系统的吞吐量。
  • 消息编码与解码:Netty提供了丰富的编码器和解码器,简化了数据协议的封装和解析。
  • 协议无关性:Netty可以用于实现多种协议,如TCP、UDP、HTTP、WebSocket等。
  • 灵活的事件模型:Netty使用基于事件的编程模型,便于开发人员理解和扩展。
  • 易于扩展:Netty允许用户自定义各种组件,如处理器、编解码器等,方便定制化需求。

开发环境搭建

为了搭建Netty开发环境,首先需要安装Java环境。Netty支持Java 8及以上版本,因此建议安装Java 8或更高版本。

# 检查Java版本
java -version

安装完成后,可以通过Maven或Gradle等构建工具引入Netty依赖。

Maven

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.68.Final</version>
</dependency>

Gradle

implementation 'io.netty:netty-all:4.1.68.Final'

第一个Netty的Hello World程序

下面是一个简单的Netty服务器端代码示例,用于监听端口并响应客户端的连接请求。客户端代码则用于连接服务器并发送"Hello, World!"消息。

服务器端代码:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LoggingHandler;

public class HelloWorldServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new StringEncoder());
                     ch.pipeline().addLast(new StringDecoder());
                     ch.pipeline().addLast(new LoggingHandler());
                     ch.pipeline().addLast(new HelloWorldServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)
             .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(8080).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

class HelloWorldServerHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("Server received: " + msg);
        ctx.writeAndFlush("Hello, World!");
    }
}

客户端代码:

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LoggingHandler;

public class HelloWorldClient {
    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .remoteHost("localhost", 8080)
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new StringEncoder());
                     ch.pipeline().addLast(new StringDecoder());
                     ch.pipeline().addLast(new LoggingHandler());
                     ch.pipeline().addLast(new HelloWorldClientHandler());
                 }
             });

            ChannelFuture f = b.connect().sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

class HelloWorldClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("Client received: " + msg);
    }
}

Netty核心概念与组件

事件循环类(EventLoop)

EventLoop是Netty的核心组件之一,它负责处理I/O事件(如读写操作、连接事件等)。EventLoop管理着一个或多个Channel,并且为每个Channel分配一个线程。在EventLoop内部,Netty使用了一个基于线程池的模型,这样可以提高系统的并发处理能力,同时减轻单个线程的负担。

每个Channel都绑定到一个EventLoop,该EventLoop负责处理该Channel的所有I/O事件。EventLoop通常在一个固定的线程上运行,保证了线程安全。

代码示例:

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();

通道(Channel)与通道管理器(ChannelHandler)

Channel表示一个网络通道,它封装了与网络通信相关的所有功能,如连接、读写、关闭等。Netty通过Channel来抽象各种协议的底层通信细节,提供统一的接口。

ChannelHandler是处理网络数据的处理器,可以添加到Channel的pipeline中。ChannelHandler分为输入处理器(ChannelInboundHandler)和输出处理器(ChannelOutboundHandler),分别处理入站和出站事件。ChannelHandler可以实现或继承多个接口,如ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter等,以简化处理逻辑。

代码示例:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(new StringEncoder());
         ch.pipeline().addLast(new StringDecoder());
         ch.pipeline().addLast(new LoggingHandler());
         ch.pipeline().addLast(new HelloWorldServerHandler());
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

缓冲区(Buffer)

Buffer是Netty用于存储和传输数据的底层对象。Netty中的Buffer对象可以理解为一个字节数组,它提供了高效的字节操作方法。Buffer对象可以被复用,以减少内存分配的开销。

Netty提供了ByteBuf接口及其实现类,如ByteBuf、CompositeByteBuf等。这些Buffer对象在物理内存和堆外内存之间进行高效切换,优化了内存使用。此外,Netty还提供了各种工厂方法来创建Buffer对象,如Unpooled、HeapByteBuf、DirectByteBuf等。

代码示例:

ByteBuf buffer = Unpooled.buffer(10);
buffer.writeBytes("Hello".getBytes());

传输与编解码(ChannelInboundHandler与ChannelOutboundHandler)

在Netty中,数据传输通常涉及编码和解码过程。ChannelHandler提供了编码器和解码器的功能,以简化协议的实现。编码器通常处理出站消息,将程序中的对象转换为字节流;解码器处理入站消息,从字节流中解析出程序对象。

常用的编码器和解码器包括:

  • LengthFieldPrepender:为消息添加长度字段。
  • LengthFieldBasedFrameDecoder:根据长度字段解析消息。
  • DelimiterBasedFrameDecoder:根据分隔符解析消息。
  • StringEncoder:将字符串编码为字节数组。
  • StringDecoder:将字节数组解码为字符串。

代码示例:

ChannelPipeline pipeline = ctx.pipeline();
pipeline.addLast(new LengthFieldPrepender(2));
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 0, 2));
pipeline.addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer("\n".getBytes())));

时间与超时处理(ChannelFuture)

ChannelFuture用于异步通知操作的结果。当异步操作完成时,ChannelFuture会触发回调,通知操作是否成功以及任何相关的异常。

channel.writeAndFlush(msg).addListener(ChannelFutureListener.FIRE_AND_FORGET);

ChannelFuture还支持超时处理。当操作在指定的时间内没有完成时,可以设置超时时间来处理超时情况。

channel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> {
    if (future.isSuccess()) {
        // 操作成功
    } else {
        // 操作失败
    }
});

Netty常用编程模型

TCP编程模型

TCP编程模型用于实现可靠的数据传输。在Netty中,TCP编程通常涉及创建一个ServerBootstrap对象来启动服务器,并使用ChannelInitializer初始化ChannelPipeline中的处理器。

代码示例:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(new StringDecoder());
         ch.pipeline().addLast(new StringEncoder());
         ch.pipeline().addLast(new HelloWorldServerHandler());
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();

UDP编程模型

UDP编程模型用于实现无连接的数据传输。在Netty中,可以使用DatagramChannel来实现UDP协议。

代码示例:

bootstrap.group(eventLoopGroup)
       .channel(DatagramChannel.class)
       .handler(new ChannelInitializer<SocketChannel>() {
           @Override
           public void initChannel(SocketChannel ch) throws Exception {
               ch.pipeline().addLast(new StringDecoder());
               ch.pipeline().addLast(new StringEncoder());
               ch.pipeline().addLast(new UdpServerHandler());
           }
       });

ChannelFuture f = bootstrap.bind(8080).sync();

HTTP/HTTPS/WS编程模型

Netty提供了内置的HTTP和WebSocket处理器,简化了HTTP/HTTPS和WebSocket的实现。

代码示例:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(HttpServerCodec.class);
         ch.pipeline().addLast(HttpObjectAggregator.class);
         ch.pipeline().addLast(RequestHandler.class);
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();

WebSocket编程模型

Netty提供了WebSocket处理器,使得实现WebSocket应用变得简单。

代码示例:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(HttpServerCodec.class);
         ch.pipeline().addLast(HttpObjectAggregator.class);
         ch.pipeline().addLast(WebSocketServerProtocolHandler.class);
         ch.pipeline().addLast(RequestHandler.class);
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();

Netty多路复用与高性能实现

Netty高性能实现原理

Netty使用了多种机制来提高性能:

  • 高效的内存管理:Netty使用ByteBuf和其他Buffer对象,通过零拷贝技术减少内存分配和复制的开销。
  • 异步非阻塞IO:Netty采用异步非阻塞I/O模型,通过事件循环处理I/O事件,提高了系统的并发处理能力。
  • 零拷贝:Netty使用了零拷贝技术,如直接内存分配和文件映射等,减少了数据复制次数。
  • 线程池复用:Netty使用线程池复用机制,避免了频繁创建和销毁线程的开销。

Netty的异步非阻塞模型

Netty的异步非阻塞模型是其高性能的重要因素。异步非阻塞模型允许应用程序在等待I/O操作完成的同时继续执行其他任务,提高了应用程序的响应性和吞吐量。

Netty的异步非阻塞模型通过事件循环和回调机制实现。当一个I/O操作完成时,事件循环会调用相应的回调函数,通知操作的结果。这样,应用程序可以充分利用CPU资源,提高系统的并发能力。

代码示例:

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(new StringDecoder());
         ch.pipeline().addLast(new StringEncoder());
         ch.pipeline().addLast(new HelloWorldServerHandler());
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();

Netty的NIO和AIO支持

Netty支持多种I/O模型,包括NIO和AIO。

NIO(Non-blocking I/O)是一种基于事件驱动的I/O模型,通过使用选择器(Selector)和通道(Channel)来实现非阻塞I/O操作。NIO可以显著提高系统的并发处理能力,适用于高并发场景。

代码示例:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(new StringDecoder());
         ch.pipeline().addLast(new StringEncoder());
         ch.pipeline().addLast(new HelloWorldServerHandler());
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();

AIO(Asynchronous I/O)是一种异步I/O模型,它基于操作系统提供的异步I/O支持。AIO模型的最大特点是操作系统直接向应用程序通知I/O事件,不需要应用程序主动查询。AIO模型适用于需要高性能和高并发的应用场景。

代码示例:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(DatagramChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ch.pipeline().addLast(new StringDecoder());
         ch.pipeline().addLast(new StringEncoder());
         ch.pipeline().addLast(new HelloWorldServerHandler());
     }
 })
 .option(ChannelOption.SO_BACKLOG, 128)
 .childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();

实战案例:简易聊天室开发

需求分析

本案例实现一个简单的多用户聊天室。服务器端负责接收和转发消息,客户端可以连接到服务器并发送消息给其他客户端。

代码实现

服务器端代码

服务器端代码接收客户端的连接请求,并转发消息给其他客户端。

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LoggingHandler;

public class ChatServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new StringEncoder());
                     ch.pipeline().addLast(new StringDecoder());
                     ch.pipeline().addLast(new ChatServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)
             .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(8080).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

class ChatServerHandler extends SimpleChannelInboundHandler<String> {
    private final List<Channel> clients = new ArrayList<>();
    private final Map<Channel, String> clientNames = new HashMap<>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        clients.remove(ctx.channel());
        clientNames.remove(ctx.channel());
        String clientName = clientNames.get(ctx.channel());
        if (clientName != null) {
            String message = clientName + "离开了聊天室";
            broadcast(ctx, message);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        if (msg.startsWith("/name ")) {
            String clientName = msg.substring(6);
            clientNames.put(ctx.channel(), clientName);
            String message = clientName + "加入了聊天室";
            broadcast(ctx, message);
        } else {
            String clientName = clientNames.get(ctx.channel());
            if (clientName == null) {
                String message = "未设置昵称,请使用 /name <昵称> 设置昵称";
                ctx.channel().writeAndFlush(message);
                return;
            }
            String message = clientName + ": " + msg;
            broadcast(ctx, message);
        }
    }

    private void broadcast(ChannelHandlerContext ctx, String message) {
        for (Channel client : clients) {
            if (client != ctx.channel()) {
                client.writeAndFlush(message);
            }
        }
    }
}
客户端代码

客户端代码连接到服务器并发送消息。

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LoggingHandler;

public class ChatClient {
    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .remoteHost("localhost", 8080)
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new StringEncoder());
                     ch.pipeline().addLast(new StringDecoder());
                     ch.pipeline().addLast(new ChatClientHandler());
                 }
             });

            ChannelFuture f = b.connect().sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

class ChatClientHandler extends SimpleChannelInboundHandler<String> {
    private final Channel channel;
    private final ConsoleCommandExecutor executor;

    public ChatClientHandler() {
        channel = null;
        executor = new ConsoleCommandExecutor();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        channel = ctx.channel();
        executor.start();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        executor.shutdown();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    private class ConsoleCommandExecutor implements Runnable {
        private volatile boolean running = true;

        public void start() {
            new Thread(this).start();
        }

        public void shutdown() {
            running = false;
        }

        @Override
        public void run() {
            Scanner scanner = new Scanner(System.in);
            while (running) {
                if (channel != null && channel.isActive()) {
                    String input = scanner.nextLine();
                    if (input.equalsIgnoreCase("exit")) {
                        running = false;
                        break;
                    }
                    channel.writeAndFlush(input);
                } else {
                    System.out.println("连接已关闭");
                    running = false;
                    break;
                }
            }
            scanner.close();
        }
    }
}

测试运行

启动服务器端代码,然后启动客户端代码。客户端可以发送消息,服务器端会将其转发给所有其他客户端。

Netty常见问题与调试

常见错误及解决方法

  • 内存溢出:检查是否存在内存泄露,合理设置堆栈大小。
  • 连接超时:增加超时时间,优化网络配置。
  • Socket错误:检查端口是否被占用,防火墙设置。
  • 编码解码错误:检查数据格式是否符合预期,验证编解码器的正确性。

性能优化技巧

  • 减少内存分配:复用Buffer对象,使用零拷贝技术。
  • 优化线程池配置:调整线程池大小,避免线程过度创建。
  • 开启HTTP缓存:使用HTTP缓存,减少网络传输。

日志与调试方法

Netty提供了多种日志记录功能,可以通过配置日志实现详细的调试信息。

import io.netty.handler.logging.LoggingHandler;

public class ChatServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new StringEncoder());
                     ch.pipeline().addLast(new StringDecoder());
                     ch.pipeline().addLast(new LoggingHandler());
                     ch.pipeline().addLast(new ChatServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)
             .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(8080).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

通过配置日志级别,可以启用详细的调试信息,帮助定位问题。

io.netty.handler.logging.LoggingHandler.level=DEBUG

使用日志配置文件或程序代码配置日志级别,可以更详细地跟踪Netty的运行状态。

这篇关于Netty网络通讯入门详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!