网络编程
#markmap
Java 网络编程的核心问题是「如何高效地收发数据」。从 BIO 到 NIO 再到 Netty,每次演进都是为了解决更高并发场景下的性能瓶颈。
IO 模型演进
IO模型 详细介绍了 Java IO 的三种模型:
| 模型 | 线程模型 | 适用场景 |
|---|---|---|
| BIO | 每连接一线程 | 低并发、连接数少 |
| NIO | 单线程多路复用 | 高并发、短连接 |
| AIO | 操作系统回调 | 高并发、长连接 |
BIO(Blocking IO)的问题在于每个 IO 操作会阻塞整个线程,线程开销随连接数线性增长。NIO(Non-blocking IO)通过 Selector(多路复用器,一个线程监听多个连接的就绪事件)实现单线程管理多连接,解决了线程膨胀问题。AIO(Asynchronous IO)进一步将 IO 操作交给操作系统完成后回调通知,但 Linux 下实现不成熟,实际收益不明显,主流方案仍是 NIO。
Netty 框架
Netty 是基于 NIO 的高性能网络框架,解决了原生 NIO 的三个痛点:
| NIO 问题 | Netty 解决方案 |
|---|---|
| API 繁杂 | 简洁的 Channel/Pipeline API |
| 多线程复杂 | EventLoop(事件循环线程,每个线程绑定一个 Selector,负责一组连接的所有 IO 事件)模型 |
| epoll bug | 修复 Selector 空轮询(JDK NIO 在 Linux epoll 下可能无事件却返回空循环,导致 CPU 100%) |
Netty 的核心设计:Channel(连接抽象)-> EventLoop(事件循环)-> ChannelPipeline(处理链,按顺序执行多个处理器)-> ChannelHandler(业务逻辑单元)。这种分层设计将网络 IO 与业务逻辑解耦。
零拷贝
零拷贝(Zero-Copy)是指数据在内核缓冲区之间直接传输,避免 CPU 在用户态和内核态之间反复拷贝数据的 IO 优化技术。IO模型 中详细介绍了原理:
| 方案 | CPU 拷贝次数 | 上下文切换 | 说明 |
|---|---|---|---|
| 传统 IO | 2 | 4 | read + write,数据经用户缓冲区中转 |
| mmap | 1 | 4 | 内核缓冲区映射到用户空间,减少一次拷贝 |
| sendfile | 1 | 2 | 数据直接在内核缓冲区间传输,不经过用户空间 |
| sendfile + DMA gather | 0 | 2 | DMA(直接内存访问,硬件直接读写内存不经过 CPU)收集多个缓冲区,CPU 零拷贝 |
Java 通过 MappedByteBuffer(mmap 对应)和 FileChannel.transferTo()(sendfile 对应)支持零拷贝。Kafka、RocketMQ、Netty 等高性能中间件依赖零拷贝减少大文件传输时的 CPU 开销。
Socket 编程
Socket(套接字)是网络通信的端点抽象,Java 通过 Socket API 封装了 TCP/UDP 的底层操作。IO 模型决定"怎么读写数据",Socket 协议决定"用什么规则通信"——两者是不同维度。
| 协议 | 特点 | 适用场景 |
|---|---|---|
| TCP | 面向连接、可靠传输、有序到达 | HTTP、RPC、文件传输 |
| UDP | 无连接、不保证可靠、延迟低 | 视频流、DNS、游戏状态同步 |
TCP 编程通过 ServerSocket/Socket 实现,BIO 模式下每个连接需要独立线程处理(这也是 IO 模型演进的驱动因素之一)。UDP 编程通过 DatagramSocket/DatagramPacket 实现,无需建立连接,每次收发独立。
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 粘包/拆包 | TCP 是字节流协议,无消息边界 | 定长消息、分隔符、长度头协议 |
| 连接超时 | 网络抖动或服务端不可达 | 设置 connectTimeout 和 soTimeout |
| 连接泄漏 | 异常路径未关闭 Socket | 使用 try-with-resources 确保关闭 |
| 端口占用 | 上次连接未完全释放(TIME_WAIT) | 设置 SO_REUSEADDR |
技术选型
选型核心考量:并发连接数、数据量大小、协议复杂度。
| 场景 | 推荐 | 选型理由 |
|---|---|---|
| 简单 TCP 服务(连接数 < 100) | BIO + 多线程 | 实现简单,调试方便,连接数少时线程开销可接受 |
| 高并发网络服务 | Netty | NIO 多路复用 + 线程模型优化,成熟社区和丰富 codec |
| 大文件传输 | NIO 零拷贝 | FileChannel.transferTo() 避免用户态拷贝,吞吐量提升显著 |
| 实时双向通信 | WebSocket + Netty | WebSocket 提供全双工通道,Netty 提供高性能底座 |
| RPC 框架开发 | Netty(Dubbo/gRPC 底层) | 自定义协议编解码、连接池管理、心跳检测开箱即用 |