当前位置: 首页 > news >正文

Java网络编程演进:从NIO到Netty的UDP实践全解析

前言

在当前高并发、大数据量的互联网环境下,高性能的网络通信框架变得越来越重要。本文将深入探讨Java网络编程的演进,从NIO到Netty,并通过实际案例分析Netty的优势和应用。(本次主要以UDP请求为例)

Java网络编程演进

传统的BIO(Blocking I/O)

  • 每个连接一个线程
  • 适用于连接数较少的场景
  • 资源消耗大,连接数增加时性能下降明显

NIO(Non-blocking I/O)

  • 引入了Channel、Buffer、Selector的概念
  • 支持非阻塞I/O操作
  • 可以用少量线程处理大量连接
  • 编程模型复杂,开发难度大

Netty

  • 基于NIO的异步事件驱动框架
  • 简化了NIO编程模型
  • 提供了丰富的协议支持和工具类
  • 高性能、高可扩展性

比较

1. 传统NIO vs Netty

特性传统NIONetty
编程复杂度较高较低
代码可维护性较差较好
内存管理手动管理自动管理(ByteBuf)
线程模型需自行实现已封装完善
处理粘包/拆包需自行实现提供多种编解码器

2. Tomcat vs Netty

特性TomcatNetty
定位Web容器网络应用框架
协议支持主要HTTP多协议支持
性能中等
使用场景Web应用通用网络服务

核心组件

1. Channel

Channel是Netty网络操作抽象类,包含了基本的I/O操作。

2. EventLoop

EventLoop负责处理注册到其上的Channel的所有I/O操作。

3. ChannelPipeline

ChannelPipeline提供了ChannelHandler链的容器,负责处理或拦截Channel的入站事件和出站操作。

网络协议支持

Netty支持多种协议,包括TCP和UDP。本文将重点介绍UDP协议的实现。

Maven依赖如下

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

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.35</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    1. NIO实现

    1.1 服务端代码

    NIO的UDP实现相对复杂,需要手动处理以下方面:

    1. 创建和配置DatagramChannel
    2. 设置非阻塞模式
    3. 创建Selector并注册Channel
    4. 实现事件循环来处理I/O事件
    5. 手动管理ByteBuffer
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.DatagramChannel;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.charset.StandardCharsets;
    import java.util.Iterator;
    import java.util.Scanner;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class NioUdpServer {
        private static final int SERVER_PORT = 8080;
        private DatagramChannel datagramChannel;
        private Selector selector;
        private final ByteBuffer buffer = ByteBuffer.allocate(1024);
        private final ConcurrentHashMap<String, InetSocketAddress> clientAddresses = new ConcurrentHashMap<>();
        private volatile boolean running = true;
    
        public void start() throws IOException {
            // 创建DatagramChannel并配置为非阻塞模式
            datagramChannel = DatagramChannel.open();
            datagramChannel.configureBlocking(false);
            datagramChannel.bind(new InetSocketAddress(SERVER_PORT));
    
            // 创建Selector并注册channel
            selector = Selector.open();
            datagramChannel.register(selector, SelectionKey.OP_READ);
    
            System.out.println("NIO UDP Server started on port " + SERVER_PORT);
    
            // 启动发送消息的线程
            Thread senderThread = new Thread(this::handleUserInput);
            senderThread.start();
    
            // 主线程处理接收消息
            while (running) {
                try {
                    if (selector.select() > 0) {
                        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                        while (iterator.hasNext()) {
                            SelectionKey key = iterator.next();
                            iterator.remove();
    
                            if (key.isReadable()) {
                                handleRead(key);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private void handleRead(SelectionKey key) throws IOException {
            DatagramChannel channel = (DatagramChannel) key.channel();
            buffer.clear();
            InetSocketAddress clientAddress = (InetSocketAddress) channel.receive(buffer);
    
            if (clientAddress != null) {
                buffer.flip();
                String message = StandardCharsets.UTF_8.decode(buffer).toString();
                System.out.println("Received from " + clientAddress + ": " + message);
    
                // 保存客户端地址
                clientAddresses.put(clientAddress.toString(), clientAddress);
    
                // 发送确认消息
                String response = "Server received: " + message;
                sendMessage(response, clientAddress);
            }
        }
    
        private void handleUserInput() {
            Scanner scanner = new Scanner(System.in);
            while (running) {
                System.out.print("Enter message to broadcast (type 'exit' to quit): ");
                String message = scanner.nextLine();
    
                if ("exit".equalsIgnoreCase(message)) {
                    running = false;
                    break;
                }
    
                // 广播消息给所有已知客户端
                broadcastMessage(message);
            }
            scanner.close();
        }
    
        private void broadcastMessage(String message) {
            for (InetSocketAddress clientAddress : clientAddresses.values()) {
                sendMessage(message, clientAddress);
            }
        }
    
        private void sendMessage(String message, InetSocketAddress address) {
            try {
                ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
                datagramChannel.send(buffer, address);
                System.out.println("Sent to " + address + ": " + message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void stop() {
            running = false;
            try {
                if (selector != null) {
                    selector.close();
                }
                if (datagramChannel != null) {
                    datagramChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            try {
                new NioUdpServer().start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    1.2 NIO实现服务端代码解析
    (1) 通道配置
    datagramChannel = DatagramChannel.open();
    datagramChannel.configureBlocking(false);
    datagramChannel.bind(new InetSocketAddress(SERVER_PORT));

    解析:

    • 手动创建 DatagramChannel,用于 UDP 传输

    • 设置非阻塞模式,提高并发处理能力

    • 显式绑定端口,监听 UDP 请求


    (2) 选择器管理
    selector = Selector.open();
    datagramChannel.register(selector, SelectionKey.OP_READ);

    解析:

    • 手动创建 Selector,用于监听多个通道

    • 注册 DatagramChannelSelector,监听 OP_READ 事件


    (3) 消息处理
    private void handleRead(SelectionKey key) throws IOException {
        DatagramChannel channel = (DatagramChannel) key.channel();
        buffer.clear();
        InetSocketAddress clientAddress = (InetSocketAddress) channel.receive(buffer);
        // 处理消息
    }

    解析:

    • 手动管理 ByteBuffer,需 flip() 切换读写模式

    • 显式处理 receive() 解析数据

    • 必须手动清理 buffer,避免数据残留

    1.3 客户端代码
    import lombok.extern.slf4j.Slf4j;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.DatagramChannel;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.charset.StandardCharsets;
    import java.util.Iterator;
    import java.util.Scanner;
    
    @Slf4j
    public class NioUdpClient {
        private static final String SERVER_HOST = "127.0.0.1";
        private static final int SERVER_PORT = 8080;
        private static final int CLIENT_PORT = 9090;
    
        private DatagramChannel datagramChannel;
        private Selector selector;
        private final ByteBuffer buffer = ByteBuffer.allocate(1024);
        private volatile boolean running = true;
    
        public void start() throws IOException {
            // 创建DatagramChannel并配置为非阻塞模式
            datagramChannel = DatagramChannel.open();
            datagramChannel.configureBlocking(false);
            datagramChannel.bind(new InetSocketAddress(CLIENT_PORT));
    
            // 创建Selector并注册channel
            selector = Selector.open();
            datagramChannel.register(selector, SelectionKey.OP_READ);
    
            log.info("NIO UDP Client 使用端口为 {}", CLIENT_PORT);
    
            // 启动发送消息的线程
            Thread senderThread = new Thread(this::handleUserInput);
            senderThread.start();
    
            // 主线程处理接收消息
            while (running) {
                try {
                    if (selector.select() > 0) {
                        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                        while (iterator.hasNext()) {
                            SelectionKey key = iterator.next();
                            iterator.remove();
    
                            if (key.isReadable()) {
                                handleRead(key);
                            }
                        }
                    }
                } catch (IOException e) {
                    log.error("");
                }
            }
        }
    
        private void handleRead(SelectionKey key) throws IOException {
            DatagramChannel channel = (DatagramChannel) key.channel();
            buffer.clear();
            InetSocketAddress serverAddress = (InetSocketAddress) channel.receive(buffer);
    
            if (serverAddress != null) {
                buffer.flip();
                String message = StandardCharsets.UTF_8.decode(buffer).toString();
                log.info("从server接收到消息: {}", message);
            }
        }
    
        private void handleUserInput() {
            Scanner scanner = new Scanner(System.in);
            while (running) {
                log.info("输入消息并按回车发送 (type 'exit' to quit): ");
                String message = scanner.nextLine();
    
                if ("exit".equalsIgnoreCase(message)) {
                    running = false;
                    break;
                }
    
                sendMessage(message);
            }
            scanner.close();
        }
    
        private void sendMessage(String message) {
            try {
                ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
                InetSocketAddress serverAddress = new InetSocketAddress(SERVER_HOST, SERVER_PORT);
                datagramChannel.send(buffer, serverAddress);
                log.info("Sent to server: {}", message);
            } catch (IOException e) {
                log.error("发送失败,{}",e.getMessage());
            }
        }
    
        public void stop() {
            running = false;
            try {
                if (selector != null) {
                    selector.close();
                }
                if (datagramChannel != null) {
                    datagramChannel.close();
                }
            } catch (IOException e) {
                log.error("关闭Selector或DatagramChannel失败,{}", e.getMessage());
            }
        }
    
        public static void main(String[] args) {
            try {
                new NioUdpClient().start();
            } catch (IOException e) {
                log.error("启动失败, {}", e.getMessage());
            }
        }
    }
    
    1.4 NIO实现客户端代码解析
    (1) 初始化
    datagramChannel = DatagramChannel.open();
    datagramChannel.configureBlocking(false);
    datagramChannel.bind(new InetSocketAddress(CLIENT_PORT));

    解析:

    • 需要手动配置通道
    • 显式设置客户端端口
    • 手动管理资源生命周期

    (2) 发送数据
    ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
    InetSocketAddress serverAddress = new InetSocketAddress(SERVER_HOST, SERVER_PORT);
    datagramChannel.send(buffer, serverAddress);

    解析:

    • 手动管理 ByteBuffer

    • 显式指定目标地址

    • 同步发送消息

    2. Netty实现

    Netty的UDP实现简洁明了,主要涉及以下几个步骤:

    1. 配置Bootstrap
    2. 设置Channel类型为NioDatagramChannel
    3. 配置ChannelHandler来处理数据收发
    2.1 服务端代码
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioDatagramChannel;
    import io.netty.channel.socket.DatagramPacket;
    import io.netty.buffer.ByteBuf;
    import io.netty.util.CharsetUtil;
    import lombok.extern.slf4j.Slf4j;
    
    import java.net.InetSocketAddress;
    @Slf4j
    public class NettyUdpServer {
    
        public static void main(String[] args) throws InterruptedException {
            // 创建事件循环组,负责处理 I/O 操作
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                // 创建引导程序,用于设置服务器参数
                Bootstrap b = new Bootstrap();
                b.group(group)
                 // 设置通道类型为 NioDatagramChannel,适用于 UDP
                 .channel(NioDatagramChannel.class)
                 // 设置处理器
                 .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
                     @Override
                     protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
                         // 获取客户端地址
                         InetSocketAddress sender = packet.sender();
                         // 获取接收到的数据
                         ByteBuf buf = packet.content();
                         String received = buf.toString(CharsetUtil.UTF_8);
                         log.info("收到来自 {} 的消息: {}", sender, received);
                         // 回复客户端
                         String response = "消息已收到: " + received;
                         ByteBuf responseBuf = ctx.alloc().buffer();
                         responseBuf.writeBytes(response.getBytes(CharsetUtil.UTF_8));
                         ctx.writeAndFlush(new DatagramPacket(responseBuf, sender));
                     }
                 });
    
                // 绑定端口并启动服务器
                ChannelFuture f = b.bind(8080).sync();
                log.info("UDP 服务器已启动,监听端口 8080");
                // 等待服务器通道关闭
                f.channel().closeFuture().await();
            } finally {
                // 关闭事件循环组
                group.shutdownGracefully();
            }
        }
    }
    
    2.2 Netty实现服务端代码解析
    (1) Bootstrap 配置
    Bootstrap b = new Bootstrap();
    b.group(group)
     .channel(NioDatagramChannel.class)
     .handler(new SimpleChannelInboundHandler<DatagramPacket>()

    解析:

    • 使用 Bootstrap 而不是 ServerBootstrap,因为 UDP 是无连接的协议

    • 使用 NioDatagramChannel 作为通道类型,专门用于 UDP 通信

    • 通过 handler 处理数据包,定义如何解析和处理接收的数据

    (2) 消息处理流程
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
        InetSocketAddress sender = packet.sender();
        ByteBuf buf = packet.content();
        String received = buf.toString(CharsetUtil.UTF_8);
        // 处理消息并回复
    }

    解析:

    • 通过 DatagramPacket 封装 UDP 数据包

    • 使用 packet.sender() 获取发送方地址

    • ByteBuf 处理二进制数据(Netty 提供的高效缓冲区)

    • 自动释放 ByteBuf,避免手动管理内存

    2.3 客户端代码
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.DatagramPacket;
    import io.netty.channel.socket.nio.NioDatagramChannel;
    import io.netty.util.CharsetUtil;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.InetSocketAddress;
    
    import lombok.AllArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    @AllArgsConstructor
    public class NettyUdpClient {
    
        private final String host;
        private final int port;
        private Channel channel;
    
    
        public void run() throws Exception {
            // 创建事件循环组
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                // 创建客户端引导程序
                Bootstrap b = new Bootstrap();
                b.group(group)
                 // 设置通道类型为 NioDatagramChannel
                 .channel(NioDatagramChannel.class)
                 // 设置处理器
                 .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
                     @Override
                     protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
                         // 接收并打印服务器的响应
                         String response = packet.content().toString(CharsetUtil.UTF_8);
                         log.info("收到服务器响应:{}", response);
                     }
    
                     @Override
                     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                         log.error("客户端异常:", cause);
                     }
                 });
    
                // 绑定随机端口并等待
                channel = b.bind(0).sync().channel();
                log.info("UDP 客户端已启动,准备发送消息...");
    
                // 从控制台读取输入并发送
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    
                // 启动一个循环,不断从控制台读取输入
                while (true) {
                    System.out.print("请输入要发送的消息(输入'exit'退出):");
                    String message = reader.readLine();
    
                    // 如果输入exit则退出
                    if ("exit".equalsIgnoreCase(message)) {
                        log.info("客户端即将关闭...");
                        break;
                    }
    
                    // 创建UDP数据包并发送
                    ByteBuf buf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
                    DatagramPacket packet = new DatagramPacket(buf, new InetSocketAddress(host, port));
    
                    // 发送消息
                    channel.writeAndFlush(packet)
                           .addListener((ChannelFutureListener) future -> {
                               if (future.isSuccess()) {
                                   log.info("消息发送成功");
                               } else {
                                   log.error("消息发送失败:{}", future.cause().getMessage());
                               }
                           });
                }
    
                // 关闭连接
                if (channel != null) {
                    channel.close().sync();
                }
    
            } finally {
                // 优雅关闭事件循环组
                group.shutdownGracefully();
            }
        }
    
        public static void main(String[] args) throws Exception {
            // 默认连接本地8080端口
            String host = "127.0.0.1";
            int port = 8080;
    
            new NettyUdpClient(host, port, null).run();
        }
    }
    

    2.4 Netty实现客户端代码解析
    (1) 初始化配置
    Bootstrap b = new Bootstrap();
    b.group(group)
     .channel(NioDatagramChannel.class)
     .handler(new SimpleChannelInboundHandler<DatagramPacket>()

    解析:

    • 与服务端类似,使用 NioDatagramChannel 处理 UDP 通信

    • 客户端不需要绑定端口,可以随机使用本地端口发送数据


    (2) 消息发送
    ByteBuf buf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
    DatagramPacket packet = new DatagramPacket(buf, new InetSocketAddress(host, port));
    channel.writeAndFlush(packet)

    解析:

    • 使用 Unpooled.copiedBuffer 创建数据缓冲区

    • DatagramPacket 封装目标地址

    • writeAndFlush 异步发送数据

    2.5 Netty小结特点
    1. 支持异步发送确认
    2. 灵活的消息收发处理
    3. 优雅的关闭机制
    4. 完善的异常处理

    Netty实现UDP双向通信

    服务端代码
    package com.lps.netty;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioDatagramChannel;
    import io.netty.channel.socket.DatagramPacket;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.util.CharsetUtil;
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.InetSocketAddress;
    import java.util.HashSet;
    import java.util.Set;
    
    @Slf4j
    public class NettyUdpBidirectionalServer {
    
        private static final int PORT = 8080;
        private static final Set<InetSocketAddress> clients = new HashSet<>();
        private static Channel serverChannel;
    
        public static void main(String[] args) throws Exception {
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap b = new Bootstrap();
                b.group(group)
                 .channel(NioDatagramChannel.class)
                 .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
                     @Override
                     protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
                         InetSocketAddress sender = packet.sender();
                         clients.add(sender); // 记录客户端地址
                         ByteBuf buf = packet.content();
                         String received = buf.toString(CharsetUtil.UTF_8);
                         log.info("【服务器】收到来自 {} 的消息: {}", sender, received);
    
                         // 回复客户端
                         String response = "服务器已收到: " + received;
                         ByteBuf responseBuf = Unpooled.copiedBuffer(response, CharsetUtil.UTF_8);
                         ctx.writeAndFlush(new DatagramPacket(responseBuf, sender));
                     }
                 });
    
                serverChannel = b.bind(PORT).sync().channel();
                log.info("【服务器】UDP 服务器已启动,监听端口 {}", PORT);
    
                // 服务器主动向客户端发送消息
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                while (true) {
                    System.out.print("【服务器】请输入要发送的消息 (输入exit退出):");
                    String message = reader.readLine();
                    if ("exit".equalsIgnoreCase(message)) {
                        break;
                    }
                    sendMessageToClients(message);
                }
            } finally {
                group.shutdownGracefully();
            }
        }
    
        // 服务器主动向所有已知客户端发送消息
        private static void sendMessageToClients(String message) {
            if (serverChannel == null || clients.isEmpty()) {
                log.warn("【服务器】没有可发送的客户端");
                return;
            }
    
            ByteBuf buf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
            for (InetSocketAddress client : clients) {
                serverChannel.writeAndFlush(new DatagramPacket(buf.retainedDuplicate(), client));
                log.info("【服务器】向 {} 发送消息: {}", client, message);
            }
        }
    }
    

    客户端代码
    package com.lps.netty;
    
    import cn.hutool.core.util.RandomUtil;
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.DatagramPacket;
    import io.netty.channel.socket.nio.NioDatagramChannel;
    import io.netty.util.CharsetUtil;
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.InetSocketAddress;
    
    @Slf4j
    
    public class NettyUdpBidirectionalClient {
    
        private static final String SERVER_HOST = "127.0.0.1";
        private static final int SERVER_PORT = 8080;
        private static final int CLIENT_PORT = 9090; // 客户端固定端口
    
        private Channel clientChannel;
    
        public static void main(String[] args) throws Exception {
            new NettyUdpBidirectionalClient().run();
        }
    
        public void run() throws Exception {
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap b = new Bootstrap();
                b.group(group)
                 .channel(NioDatagramChannel.class)
                 .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
                     @Override
                     protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
                         String response = packet.content().toString(CharsetUtil.UTF_8);
                         log.info("【客户端】收到服务器的消息: {}", response);
                     }
                 });
    
                clientChannel = b.bind(RandomUtil.randomInt(9000,10001)).sync().channel();
                log.info("【客户端】UDP 客户端已启动,监听端口 {}", RandomUtil.randomInt(9000,10001));
    
                // 发送消息到服务器
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                while (true) {
                    System.out.print("【客户端】请输入要发送的消息 (输入'exit'退出):");
                    String message = reader.readLine();
                    if ("exit".equalsIgnoreCase(message)) {
                        break;
                    }
                    sendMessageToServer(message);
                }
            } finally {
                group.shutdownGracefully();
            }
        }
    
        // 发送消息到服务器
        private void sendMessageToServer(String message) {
            ByteBuf buf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
            DatagramPacket packet = new DatagramPacket(buf, new InetSocketAddress(SERVER_HOST, SERVER_PORT));
            clientChannel.writeAndFlush(packet);
            log.info("【客户端】发送消息到服务器: {}", message);
        }
    }
    

    核心类和方法解析

     Netty 核心类

    类名作用
    Bootstrap用于启动 Netty 客户端或无连接的服务端
    NioDatagramChannel适用于 UDP 的 Netty 通道
    DatagramPacketUDP 数据包封装

     NIO核心类

    类名作用
    DatagramChannelNIO 提供的 UDP 通道
    Selector多路复用器,监听多个通道
    ByteBufferNIO 的缓冲区管理

    Netty vs. NIO 对比分析

    特性NettyNIO
    代码复杂度
    内存管理自动手动
    异步处理内置支持需要自行实现
    异常处理统一完善需手动处理
    扩展性一般

    总结

    通过对比NIO和Netty的实现,我们可以清楚地看到Netty在简化网络编程、提高开发效率和性能方面的优势。Netty不仅封装了复杂的NIO操作,还提供了丰富的功能和优化措施,使得开发高性能网络应用变得更加容易。

    随着技术的不断发展,保持学习和实践的态度,将帮助我们在网络编程领域不断提升。无论是使用NIO还是Netty,核心都是要理解网络编程的基本原理。

    相关文章:

  1. Java HMAC加密/解密详解
  2. 优化程序命名:提升专业感与用户体验
  3. 《孟婆汤的SHA-256加密》
  4. 51单片机的五类指令(一)——数据传送类指令
  5. 微服务核心知识点深度解析:从组件到架构设计
  6. 《边缘计算风云录:FPGA与MCU的算力之争》
  7. [MySQL数据库] InnoDB存储引擎(一) : MySQL架构与常见存储引擎
  8. Python实现概率分布公式及可视化
  9. MySQL 的事务
  10. 乡土中国--农村和城市生态的区别
  11. 笔试专题(五)
  12. 瑞芯微RKRGA(librga)Buffer API 分析
  13. 8.4考研408简单选择排序与堆排序知识点深度解析
  14. vue3为什么要用引入Composition api
  15. PyTorch版本过低导致属性错误-Linux服务器
  16. 【操作系统】软中断vs硬中断
  17. 探索量子世界的钥匙:薛定谔与薛定谔方程
  18. 手机上(ios安卓)如何打开网页控制台
  19. WPS宏开发手册——Excel常用Api
  20. 解决前端项目中无法识别 .node 文件的依赖安装问题
  21. .net网站做优化/什么推广软件效果好
  22. 中国免费建站网/深圳网站建设维护
  23. 网站展示怎么做/seo优化网络公司排名
  24. 网站设计的公司怎么样/个人永久免费自助建站
  25. 网站空间数据库/提高搜索引擎检索效果的方法
  26. 什么样的公司专业做网站的/seo网站优化公司