第 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):一个线程管理多个连接。
| 模型 | 线程模型 | 适用 |
|---|---|---|
| BIO | 1 连接 : 1 线程 | 连接数少(< 1000) |
| NIO | 1 线程 : N 连接 | 高并发(Netty/Tomcat NIO) |
NIO 三大组件(知道就行):
| 组件 | 作用 |
|---|---|
Channel | 双向通道,可读可写 |
Buffer | 数据容器(读写切换靠 flip()) |
Selector | 一个线程监听多个 Channel 的就绪事件 |
企业现状:直接用 Netty(基于 NIO 的高性能框架),不要自己写 NIO 代码。
三、Netty 是什么
Netty = 基于 NIO 的异步事件驱动网络框架,几乎所有 Java 高并发中间件都用它:
| 项目 | 用 Netty 干啥 |
|---|---|
| Dubbo | RPC 通信 |
| RocketMQ | 消息队列通信 |
| Elasticsearch | 节点间传输 |
| gRPC | RPC 框架 |
典型 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 的应用层协议 |
| Socket | TCP 通信的端点 |
| 端口 | 0-65535,80=HTTP,443=HTTPS,3306=MySQL |
六、本章小结
| 要点 | 关键 |
|---|---|
| BIO | 一个连接一个线程,连接多就 OOM |
| NIO | 一个线程管多个连接,Selector 多路复用 |
| Netty | 基于 NIO 的工业级框架,Java 高并发标配 |
| 何时用 | 业务代码不需要自己写 NIO,用 Netty 或 HTTP 客户端 |
动手练习
- BIO Echo:写一个简单 Socket 服务器,接收客户端消息并回显(理解阻塞)
- HTTP 客户端:用
HttpClient(JDK 11+)发一个 GET 请求 - 端口扫盲:用
ServerSocket(0)让系统自动分配端口,打印出来
下一章:第 21 章:线程基础 →