Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java IO,NIO以及Netty网络编程

Java IO,NIO以及Netty网络编程

原创
作者头像
AnieaLanie
修改于 2021-12-11 09:05:10
修改于 2021-12-11 09:05:10
78200
代码可运行
举报
文章被收录于专栏:铁子的专栏铁子的专栏
运行总次数:0
代码可运行

1. IO,NIO和Netty简介

1.1 阻塞 IO(Blocking I/O)

同步阻塞I/O模式:当一条线程执行 read() 或者 write() 方法时,这条线程会一直阻塞直到读取一些数据或者写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。

但是,当面对十万甚至百万级连接的时候,传统的 BIO模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

1.2 非阻塞 NIO(New I/O)

NIO是一种同步非阻塞的 I/O模型,NIO 与原有的 IO 有同样的作用和目的,但是使用的方式完全不同,NIO 支持面向缓冲区、基于通道的操作。NIO 将以更加高效的方式进行文件读写操作。 JAVA NIO的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO系统,需要获取用于连接 IO设备的通道以及用于容纳数据的缓冲区数据进行处理。阻塞IO 会一直等待,所以非阻塞IO 是用来解决 IO线程与 Socket 之间的解耦问题,通过引入机制如果 Socket 发送缓冲区可写的话会通知 IO线程进行 write,如果 Socket 的接收缓冲区可读的话会通知 IO线程进行 read。NIO 提供了与传统 BIO 模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel。

对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

1.3 Netty

Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

Netty 是一个 NIO 客户端服务器框架,可以快速轻松地开发网络应用程序,例如协议服务器和客户端。它极大地简化和精简了 TCP 和 UDP 套接字服务器等网络编程。

“快速而简单”并不意味着生成的应用程序会受到可维护性或性能问题的影响。Netty 是根据从许多协议(如 FTP、SMTP、HTTP 以及各种基于二进制和文本的遗留协议)的实现中获得的经验而精心设计的。结果,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

2. 编码

2.1 IO服务端
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class OioServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
​
    ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
    //创建socket服务,监听10101端口
    ServerSocket server=new ServerSocket(10101);
    System.out.println("服务器启动!");
    while(true){
        //获取一个套接字(阻塞)
        final Socket socket = server.accept();
        System.out.println("来个一个新客户端!");
        newCachedThreadPool.execute(new Runnable() {
​
            @Override
            public void run() {
                //业务处理
                handler(socket);
            }
        });}
}/**
 * 读取数据
 * @param socket
 * @throws Exception
 */
public static void handler(Socket socket){
    try {
        byte[] bytes = new byte[1024];
        InputStream inputStream = socket.getInputStream();while(true){
            //读取数据(阻塞)
            int read = inputStream.read(bytes);
            if(read != -1){
                System.out.println(new String(bytes, 0, read));
            }else{
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        try {
            System.out.println("socket关闭");
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}}
2.2 NIO服务端
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;public class NIOServer {
// 通道管理器
private Selector selector;
/**
 * 获得一个ServerSocket通道,并对该通道做一些初始化的工作
 *
 * @param port
 *            绑定的端口号
 * @throws IOException
 */
public void initServer(int port) throws IOException {
    // 获得一个ServerSocket通道
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    // 设置通道为非阻塞
    serverChannel.configureBlocking(false);
    // 将该通道对应的ServerSocket绑定到port端口
    serverChannel.socket().bind(new InetSocketAddress(port));
    // 获得一个通道管理器
    this.selector = Selector.open();
    // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
    // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
    serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}/**
 * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
 *
 * @throws IOException
 */
public void listen() throws IOException {
    System.out.println("服务端启动成功!");
    // 轮询访问selector
    while (true) {
        // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
        selector.select();
        // 获得selector中选中的项的迭代器,选中的项为注册的事件
        Iterator<?> ite = this.selector.selectedKeys().iterator();
        while (ite.hasNext()) {
            SelectionKey key = (SelectionKey) ite.next();
            // 删除已选的key,以防重复处理
            ite.remove();handler(key);
        }
    }
}/**
 * 处理请求
 *
 * @param key
 * @throws IOException
 */
public void handler(SelectionKey key) throws IOException {// 客户端请求连接事件
    if (key.isAcceptable()) {
        handlerAccept(key);
        // 获得了可读的事件
    } else if (key.isReadable()) {
        handelerRead(key);
    }
}/**
 * 处理连接请求
 *
 * @param key
 * @throws IOException
 */
public void handlerAccept(SelectionKey key) throws IOException {
    ServerSocketChannel server = (ServerSocketChannel) key.channel();
    // 获得和客户端连接的通道
    SocketChannel channel = server.accept();
    // 设置成非阻塞
    channel.configureBlocking(false);// 在这里可以给客户端发送信息哦
    System.out.println("新的客户端连接");
    // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
    channel.register(this.selector, SelectionKey.OP_READ);
}/**
 * 处理读的事件
 *
 * @param key
 * @throws IOException
 */
public void handelerRead(SelectionKey key) throws IOException {
    // 服务器可读取消息:得到事件发生的Socket通道
    SocketChannel channel = (SocketChannel) key.channel();
    // 创建读取的缓冲区
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int read = channel.read(buffer);
    if(read > 0){
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("服务端收到信息:" + msg);//回写数据
        ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
        channel.write(outBuffer);// 将消息回送给客户端
    }else{
        System.out.println("客户端关闭");
        key.cancel();
    }
}/**
 * 启动服务端测试
 *
 * @throws IOException
 */
public static void main(String[] args) throws IOException {
    NIOServer server = new NIOServer();
    server.initServer(8000);
    server.listen();
}
}
2.3 Netty回声服务器
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package Netty;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
​
​
public final class EchoServer {static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));public static void main(String[] args) throws Exception {
  // Configure SSL.
  final SslContext sslCtx;
  if (SSL) {
          SelfSignedCertificate ssc = new SelfSignedCertificate();
          sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
      } else {
          sslCtx = null;
      }// 配置服务器
  EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  EventLoopGroup workerGroup = new NioEventLoopGroup();
  final EchoServerHandler serverHandler = new EchoServerHandler();
  try {
          ServerBootstrap b = new ServerBootstrap();
          b.group(bossGroup, workerGroup)
           .channel(NioServerSocketChannel.class)
           .option(ChannelOption.SO_BACKLOG, 100)
           .handler(new LoggingHandler(LogLevel.INFO))
           .childHandler(new ChannelInitializer<SocketChannel>() {
           @Override
           public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            if (sslCtx != null) {
                                    p.addLast(sslCtx.newHandler(ch.alloc()));
                                }
                            //p.addLast(new LoggingHandler(LogLevel.INFO));
                            p.addLast(serverHandler);
                        }
       });// 启动服务器
          ChannelFuture f = b.bind(PORT).sync();// 阻塞直到断开连接
          f.channel().closeFuture().sync();
      } finally {
          // 关闭所有事件循环并关闭线程
          bossGroup.shutdownGracefully();
          workerGroup.shutdownGracefully();
      }
}
}

服务端处理事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package Netty;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;import java.nio.charset.StandardCharsets;
import java.util.Scanner;
​
​
@Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
​
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        Scanner s = new Scanner(System.in);
        while(true) {
            String words = s.nextLine();
            final ByteBuf wordbuf = Unpooled.wrappedBuffer(words.getBytes(StandardCharsets.UTF_8));
           
            final ChannelFuture f = ctx.writeAndFlush(wordbuf); // (3)
​
            f.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) {
                    assert f == future;
                    if(words.equals("exit")){
                        ctx.close();
                        return;
                    }}
            }); // (4)
        }
    }
​
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }
​
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

服务端:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package Netty;/*
   * Copyright 2012 The Netty Project
   *
   * The Netty Project licenses this file to you under the Apache License,
   * version 2.0 (the "License"); you may not use this file except in compliance
   * with the License. You may obtain a copy of the License at:
   *
   *   https://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations
   * under the License.
   */import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
​
​
public final class EchoClient {
    static final boolean SSL = System.getProperty("ssl") != null;
    static final String HOST = System.getProperty("host", "127.0.0.1");
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
    static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));public static void main(String[] args) throws Exception {
        // Configure SSL.git
        final SslContext sslCtx;
        if (SSL) {
                sslCtx = SslContextBuilder.forClient()
                    .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
            } else {
                sslCtx = null;
            }// Configure the client.
        EventLoopGroup group = new NioEventLoopGroup();
        try {
                Bootstrap b = new Bootstrap();
                b.group(group)
                 .channel(NioSocketChannel.class)
                 .option(ChannelOption.TCP_NODELAY, true)
                 .handler(new ChannelInitializer<SocketChannel>() {
               @Override
        public void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        if (sslCtx != null) {
                                p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
                            }
                        //p.addLast(new LoggingHandler(LogLevel.INFO));
                      p.addLast(new EchoClientHandler());
                  }
  });// Start the client.
                 ChannelFuture f = b.connect(HOST, PORT).sync();// 等待直到服务端关闭连接
                 f.channel().closeFuture().sync();
             } finally {
                 // Shut down the event loop to terminate all threads.
                 group.shutdownGracefully();
             }
     }
}

客户端处理事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package Netty;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;import java.util.Date;/**
* Handler implementation for the echo client.  It initiates the ping-pong
* traffic between the echo client and server by sending the first message to
* the server.
*/
      public class EchoClientHandler extends ChannelInboundHandlerAdapter {private final ByteBuf firstMessage;/**
    * Creates a client-side handler.
    */
          public EchoClientHandler() {
              firstMessage = Unpooled.buffer(EchoClient.SIZE);
              for (int i = 0; i < firstMessage.capacity(); i ++) {
                firstMessage.writeByte((byte) i);
            }
    }
​
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(firstMessage);
    }
​
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf m = (ByteBuf) msg; // (1)
        String word=m.toString(CharsetUtil.UTF_8);
        try {
            System.out.println(word);
            if(word.equals("exit")){
                ctx.close();
            }} finally {
            m.release();
        }
    }
​
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
       ctx.flush();
    }
​
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

该程序允许从服务端向客户端发送消息:

发送方:

接收方:

3. 参考

[1] Netty3学习笔记(一) --- 传统IO与NIO比较

[2] Netty3学习笔记(二) --- Netty Helloworld入门

[3] Netty回声服务器

[4] Java面试——Netty

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从NIO到Netty开发
文章转自:https://blog.csdn.net/qq285016127/article/details/80393951 1. 从传统BIO到NIO的升级 Client/Server模型是网络编程的基本模型,服务端提供位置信息,客户端通过连接操作向服务端发起连接请求,通过三次握手建立连接,如果连接建立成功,双方就可以通过网络套接字(Socket)进行通信。 传统的Socket编程是服务端一直处于accpet阻塞等待的状态,并且只有客户端发送了请求,服务才会从阻塞状态变成处理任务的状态,当任务处理完了,
Java高级架构
2018/07/20
5980
Java网络编程--Netty入门
Netty是一个高性能,高可扩展性的异步事件驱动的网络应用程序框架,它极大的简化了TCP和UDP客户端和服务器端网络开发。它是一个NIO框架,对Java NIO进行了良好的封装。作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。
CodingDiray
2019/09/25
5800
Java网络编程--Netty入门
Netty学习一
前面我们已经学习了NIO的简单知识,三大组件:ByteBuffer、Channel、Selector。知道ByteBufffer是数据,而Channel是数据的载体通道,selector为多路复用。如果说线程池为线程提供了重复利用的途径,而Selector则为起到了调度线程的目的,也即高效率的使用线程。下面我们开始Netty的学习。
路行的亚洲
2020/07/16
4220
史诗级最强教科书式“NIO与Netty编程”
java.nio全称java non-blocking IO,是指JDK1.4开始提供的新API。从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,也被称为NIO(既New IO),新增了许多用于处理输入输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写,新增类满足NIO的功能。 NIO和BIO有着相同的目的和作用,但是它们的实现方式完全不同,BIO以流的方式处理数据,而NIO以块的方式处理数据,块I/O的效率比流I/O高很多。另外,NIO是非阻塞式的,这一点跟BIO也很不相同,使用它可以提供非阻塞式的高伸缩性网络。 NIO主要有三大核心部分 :Channel(通道),Buffer(缓冲区),Selector(选择器)。传统的BIO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如 :连接打开,数据到达)。因此使用单个线程就可以监听多个数据管道。
海仔
2019/08/26
9560
史诗级最强教科书式“NIO与Netty编程”
Netty之旅三:Netty服务端启动源码分析,一梭子带走!
哈喽,自从上篇《Netty之旅二:口口相传的高性能Netty到底是什么?》后,迟迟两周才开启今天的Netty源码系列。源码分析的第一篇文章,下一篇我会分享客户端的启动过程源码分析。通过源码的阅读,我们将会知道,Netty 服务端启动的调用链是非常长的,同时肯定也会发现一些新的问题,随着我们源码阅读的不断深入,相信这些问题我们也会一一攻破。
一枝花算不算浪漫
2020/09/17
5680
Netty之旅三:Netty服务端启动源码分析,一梭子带走!
Netty学习笔记(一)
Netty是一种可以轻松快速的开发类似协议服务器和客户端网络应用程序的NIO客户端服务器框架,它大大简化了TCP或者UDP服务器的网络编程,但是你仍然可以访问和使用底层的APIs,因为Netty提供了高层的抽象。
加多
2018/09/06
7180
Netty学习笔记(一)
你对Java网络编程了解的如何?Java NIO 网络编程 | Netty前期知识(二)
在 Java 1.4 中引入了 NIO 框架(java.nio 包),提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层的高性能数据操作方式
宁在春
2022/10/31
3330
你对Java网络编程了解的如何?Java NIO 网络编程 | Netty前期知识(二)
【Netty】NIO编程的利器
今天换换口味,由于本人工作中马上要用到Netty这个东西,所以这几天也是开始学习,此学习过程应该会是一个完整的系列,初步的目标是先会用,之后有机会再深入。鉴于笔者之前也从未使用过Netty,所以有什么疏漏错误的,希望大家指正,先行感谢!
周三不加班
2019/09/04
4150
【Netty】NIO编程的利器
高性能通讯框架——Netty
编程复杂,缓冲区Buffer要考虑读写指针切换。而Netty把它封装之后,进行优化并提供了一个易于操作的使用模式和接口,因此Netty就被广泛使用于通信框架。
IT大咖说
2021/04/08
7650
剖析Netty内部网络实现原理
我在前面的几篇文章中分享了 Redis、Nginx 的网络模块内部实现原理。今天我就再带大家来了解一下 Netty 的网络内部实现。
开发内功修炼
2022/12/07
7440
剖析Netty内部网络实现原理
Netty网络编程第四卷
提供两个实现,我这里直接将实现加入了枚举类 Serializer.Algorithm 中
大忽悠爱学习
2022/05/06
6060
Netty网络编程第四卷
Java 聊天室基于Netty
Netty在服务断端口绑定和新连接建立的过程中都会建立相应的channel,pipeline就像是一条流水线,被分为许多加工环节,字节流在流水线上加工。
AnieaLanie
2021/12/11
1.1K0
java架构之路-(netty专题)初步认识BIO、NIO、AIO
  本次我们主要来说一下我们的IO阻塞模型,只是不多,但是一定要理解,对于后面理解netty很重要的
小菜的不能再菜
2020/02/21
4640
netty源码分析之 server端的源码分析
group.channel(NioServerSocketChannel.class) 根据源码以及在分析客户端源码很容易看出来服务端channel的初始化
用户1418372
2019/03/01
6870
netty源码分析之三Bootstrap初始化
可以看到childGroup也就是group方法传入的workerGroup是赋值给ServerBootstrap的childGroup属性的。我们进入 super.group(parentGroup)也就是io.netty.bootstrap.AbstractBootstrap#group(io.netty.channel.EventLoopGroup):
山行AI
2019/10/24
1.3K0
Java IO 模型之 BIO,NIO,AIO
应用场景:BIO 适合用于连接数比较小且固定的架构,这种方式对服务器资源要求比较高,但程序简单易理解。
Se7en258
2021/05/18
6820
Java IO 模型之 BIO,NIO,AIO
Netty 应用与原理
在 I/O 操作中有这么两组概念,其中同步/异步 要和线程中的同步线程/异步线程要区分开,这里指的是同步IO / 异步IO
浪漫主义狗
2024/04/27
2760
Netty 应用与原理
IO 与 NIO之网络通信
IO 与 NIO之网络通信
Java架构师必看
2021/05/14
4090
IO 与 NIO之网络通信
45 张图深度解析 Netty 架构与原理
接下来我们会学习一个 Netty 系列教程,Netty 系列由「架构与原理」,「源码」,「架构」三部分组成,今天我们先来看看第一部分:Netty 架构与原理初探,大纲如下:
kunge
2020/11/27
25.9K4
Netty之JavaNIO编程模型介绍02
  NIO 非阻塞 网络编程相关的(Selector、SelectionKey、ServerScoketChannel和SocketChannel) 关系梳理图
用户4919348
2019/12/31
5250
相关推荐
从NIO到Netty开发
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验