Skip to content
第 20 章 后端 ⏱ 6 分钟阅读

第 20 章:NIO 简述与网络编程入门 ​

学习目标 ​

  • 知道 BIO / NIO 的区别
  • 了解 Netty 是干什么的
  • 知道什么时候用 NIO

一、BIO 的问题(为什么需要 NIO) ​

BIO(Blocking IO):一个连接占一个线程。1 万连接 = 1 万线程 → OOM。

java
// BIO 服务端:每个连接开一个线程
ServerSocket server = new ServerSocket(8080);
while (true) {
    Socket socket = server.accept();   // 阻塞等连接
    new Thread(() -> {
        // 处理 socket
    }).start();                        // 每个连接 = 一个线程
}

为什么慢? 每个线程栈 1MB,1 万线程要 10GB 内存,CPU 大把时间花在线程切换。

二、NIO 的核心思路 ​

NIO(Non-blocking IO):一个线程管理多个连接。

模型线程模型适用
BIO1 连接 : 1 线程连接数少(< 1000)
NIO1 线程 : N 连接高并发(Netty/Tomcat NIO)

NIO 三大组件(知道就行):

组件作用
Channel双向通道,可读可写
Buffer数据容器(读写切换靠 flip())
Selector一个线程监听多个 Channel 的就绪事件

企业现状:直接用 Netty(基于 NIO 的高性能框架),不要自己写 NIO 代码。

三、Netty 是什么 ​

Netty = 基于 NIO 的异步事件驱动网络框架,几乎所有 Java 高并发中间件都用它:

项目用 Netty 干啥
DubboRPC 通信
RocketMQ消息队列通信
Elasticsearch节点间传输
gRPCRPC 框架

典型 Netty 服务器代码(知道结构,不要背):

java
public class NettyServer {
    public static void main(String[] args) {
        EventLoopGroup boss = new NioEventLoopGroup(1);     // 接收连接
        EventLoopGroup worker = new NioEventLoopGroup();    // 处理 IO

        ServerBootstrap b = new ServerBootstrap();
        b.group(boss, worker)
         .channel(NioServerSocketChannel.class)
         .childHandler(new ChannelInitializer<SocketChannel>() {
             @Override
             protected void initChannel(SocketChannel ch) {
                 ch.pipeline().addLast(new MyHandler());
             }
         });

        b.bind(8080).sync();   // 监听 8080
    }
}

四、什么时候用 NIO? ​

99% 的业务代码不需要碰 NIO:

  • ✅ 业务代码用 HTTP 客户端(Spring 的 RestTemplate / WebClient)就够了
  • ✅ 用 Netty 时,直接调框架 API,不用懂底层 Selector
  • ❌ 不要自己从零写 NIO Selector 代码(容易出 bug)

五、网络编程基础概念 ​

概念一句话
TCP面向连接、可靠传输(三次握手)
UDP无连接、可能丢包、但快
HTTP基于 TCP 的应用层协议
SocketTCP 通信的端点
端口0-65535,80=HTTP,443=HTTPS,3306=MySQL

六、本章小结 ​

要点关键
BIO一个连接一个线程,连接多就 OOM
NIO一个线程管多个连接,Selector 多路复用
Netty基于 NIO 的工业级框架,Java 高并发标配
何时用业务代码不需要自己写 NIO,用 Netty 或 HTTP 客户端

动手练习 ​

  1. BIO Echo:写一个简单 Socket 服务器,接收客户端消息并回显(理解阻塞)
  2. HTTP 客户端:用 HttpClient(JDK 11+)发一个 GET 请求
  3. 端口扫盲:用 ServerSocket(0) 让系统自动分配端口,打印出来

下一章:第 21 章:线程基础 →

本站基于 VitePress 构建 · 由 StackHub 团队维护