整体知识体系脑图

Java网络通信底层
│
├── 计算机网络基础
│   ├── OSI七层
│   ├── TCP/IP
│   ├── Socket
│   ├── 内核态/用户态
│   └── DMA
│
├── TCP
│   ├── 三次握手
│   ├── 四次挥手
│   ├── 滑动窗口
│   ├── 拥塞控制
│   ├── 粘包拆包
│   └── TIME_WAIT
│
├── UDP
│   ├── 无连接
│   ├── 不可靠
│   ├── RTP
│   ├── QUIC
│   └── WebRTC
│
├── Java IO
│   ├── BIO
│   ├── NIO
│   ├── AIO
│   ├── Selector
│   └── DirectBuffer
│
├── Linux IO模型
│   ├── select
│   ├── poll
│   ├── epoll
│   ├── Reactor
│   └── Proactor
│
├── Netty
│   ├── EventLoop
│   ├── Pipeline
│   ├── ByteBuf
│   ├── 零拷贝
│   └── 内存池
│
└── Tomcat
    ├── Connector
    ├── Acceptor
    ├── Poller
    ├── Coyote
    ├── Catalina
    └── Servlet

第一章:网络通信本质


1.1 什么是网络通信

网络通信的本质:

两个进程之间的数据交换

注意:

不是两个机器。

真正通信的是:

进程 <-> 进程

浏览器:

Chrome进程

Tomcat:

Java进程

1.2 浏览器访问 Tomcat 到底发生了什么

当你输入:

http://localhost:8080/index

实际上发生:

浏览器
 ↓
DNS解析
 ↓
获取IP
 ↓
TCP建立连接
 ↓
发送HTTP请求
 ↓
网卡
 ↓
Linux内核
 ↓
Socket缓冲区
 ↓
Tomcat NIO线程
 ↓
Servlet
 ↓
返回Response

1.3 网络通信本质 = Socket

Socket:

操作系统提供的网络通信抽象

本质:

文件描述符(fd)

Linux:

一切皆文件

所以:

  • 磁盘文件
  • Socket
  • 管道
  • 网卡

都对应:

fd

1.4 Socket 本质

创建 Socket:

Socket socket = new Socket("127.0.0.1",8080);

本质:

Java JNI 调用:

socket()

Linux 内核创建:

struct socket

同时:

分配fd

例如:

fd = 5

1.5 内核态与用户态

这是网络编程核心。

应用程序:

用户态

操作系统:

内核态

用户态不能直接操作:

  • 网卡
  • 内存
  • 中断
  • DMA

所以必须:

系统调用

例如:

socket.read()

本质:

recv()

CPU切换:

用户态 -> 内核态

这个过程:

上下文切换

成本很高。


1.6 数据为什么能到达 Tomcat

核心流程:

浏览器发送数据
    ↓
网卡收到二进制数据
    ↓
DMA复制到内核缓冲区
    ↓
TCP协议栈处理
    ↓
放入Socket接收缓冲区
    ↓
epoll通知Tomcat
    ↓
Tomcat读取数据

1.7 DMA 是什么

DMA:

Direct Memory Access

传统IO:

磁盘 -> CPU -> 内存

DMA:

磁盘 -> 内存

CPU不参与数据搬运。

所以:

减少CPU消耗

1.8 一次 read() 发生了什么

inputStream.read();

本质:

read系统调用

Linux:

recv()

发生:

用户态buffer
    ↑
copy
    ↑
Socket缓冲区

这里有:

数据拷贝

性能损耗巨大。


1.9 零拷贝

传统:

磁盘 -> 内核buffer
内核buffer -> 用户buffer
用户buffer -> socket buffer
socket buffer -> 网卡

4次拷贝。

零拷贝:

sendfile()

直接:

磁盘buffer -> 网卡

Tomcat:

支持sendfile

Netty:

支持零拷贝

第二章:TCP 深度原理


2.1 TCP 为什么可靠

TCP保证:

  • 不丢
  • 不乱
  • 不重复
  • 按序

核心:

序列号 + ACK + 重传

2.2 TCP 三次握手

流程:

客户端        服务端

SYN  -------->

      <-------- SYN + ACK

ACK  -------->

2.3 为什么不能两次握手

因为服务端不知道:

客户端是否收到ACK

如果只有两次:

服务端可能误认为连接成功。


2.4 SYN Flood

攻击:

大量发送SYN
不发送ACK

导致:

半连接队列打满

Tomcat无法建立连接。


2.5 半连接队列

收到 SYN:

连接未完成

放入:

SYN Queue

收到 ACK:

进入:

Accept Queue

2.6 四次挥手

FIN
ACK
FIN
ACK

为什么四次?

因为:

TCP是全双工

双方必须分别关闭。


2.7 TIME_WAIT

主动关闭方:

TIME_WAIT

作用:

防止旧包影响新连接

保证最后ACK到达


2.8 为什么会粘包

TCP:

面向字节流

不是消息。

所以:

可能连续发送

接收方:

不知道边界

2.9 如何解决粘包

方案:

固定长度

100字节

分隔符

\n

length字段

消息头 + length

Netty:

LengthFieldBasedFrameDecoder

第三章:Java BIO/NIO


3.1 BIO 模型

while(true){
    Socket socket = server.accept();

    new Thread(()->{
        socket.read();
    }).start();
}

问题:

一个连接一个线程

10万连接:

10万个线程

直接炸。


3.2 阻塞本质

socket.read()

线程:

阻塞等待数据

CPU浪费严重。


3.3 NIO 核心

核心:

一个线程管理多个连接

3.4 Selector 本质

Java:

selector.select()

本质:

Linux:

epoll_wait()

3.5 epoll 为什么快

select:

遍历所有fd

epoll:

事件通知

核心:

回调机制

3.6 Reactor 模型

核心:

事件驱动

流程:

连接来了
 ↓
Reactor监听
 ↓
事件分发
 ↓
Handler处理

第四章:Tomcat 网络通信架构(核心)


4.1 Tomcat 架构

Server
 └── Service
      ├── Connector
      └── Container

4.2 Connector 核心

Connector负责:

网络通信

包括:

  • TCP
  • HTTP解析
  • Socket管理

4.3 Tomcat NIO 模型

核心线程:

Acceptor
Poller
Worker

4.4 Acceptor

负责:

accept连接

本质:

accept()

4.5 Poller

负责:

epoll_wait

监听:

读写事件

4.6 SocketProcessor

收到事件:

封装任务

交给线程池。


4.7 完整请求流程

浏览器
 ↓
TCP
 ↓
Socket
 ↓
Acceptor
 ↓
Poller
 ↓
SocketProcessor
 ↓
HTTP解析
 ↓
CoyoteAdapter
 ↓
Engine
 ↓
Host
 ↓
Context
 ↓
Wrapper
 ↓
Servlet

4.8 Tomcat 为什么高并发

核心:

NIO

epoll

Reactor

线程池


4.9 Tomcat Reactor 模型

Tomcat:

主从Reactor

主Reactor:

Acceptor

从Reactor:

Poller

Worker:

业务处理

4.10 HTTP 请求解析

Tomcat:

Http11Processor

解析:

RequestLine
Header
Body

4.11 keep-alive

HTTP1.1默认:

长连接

Tomcat:

不会立即关闭Socket。

减少:

TCP握手成本

第五章:Netty 为什么快


5.1 Netty 核心

Reactor + epoll + 零拷贝

5.2 EventLoop

本质:

死循环线程

负责:

  • IO
  • 任务
  • 定时任务

5.3 ByteBuf

替代:

ByteBuffer

优势:

  • 动态扩容
  • 池化
  • 零拷贝

5.4 Netty 如何减少 GC

核心:

内存池

类似:

Redis内存池

避免:

频繁new byte[]

5.5 Netty 如何解决粘包

内置:

LengthFieldBasedFrameDecoder
DelimiterBasedFrameDecoder

第六章:Linux epoll 底层


6.1 select 为什么慢

select:

每次复制fd集合

并且:

线性遍历

复杂度:

O(n)

6.2 epoll 核心

epoll:

红黑树 + 链表

6.3 epoll_create

创建:

eventpoll对象

6.4 epoll_ctl

注册fd:

加入红黑树

6.5 epoll_wait

阻塞等待事件。

有事件:

直接返回就绪链表

无需遍历全部fd。


第七章:百万连接架构


7.1 Redis 为什么快

Redis:

单线程 + epoll

避免:

线程切换

7.2 Kafka 为什么吞吐高

Kafka:

顺序IO

零拷贝

批量发送


7.3 Nginx 为什么抗高并发

核心:

多进程 + epoll

7.4 百万 IM 架构

客户端
   ↓
LB
   ↓
Gateway(Netty)
   ↓
MQ(Kafka)
   ↓
业务集群
   ↓
Redis路由

第八章:源码调试


8.1 调试 Tomcat

断点:

NioEndpoint#Poller

观察:

epoll事件处理

8.2 调试 Netty

断点:

NioEventLoop#run

理解:

事件循环

8.3 抓包分析

tcpdump -i eth0 port 8080

Wireshark:

观察:

  • SYN
  • ACK
  • FIN

8.4 jstack 分析线程

jstack pid

分析:

  • BLOCKED
  • WAITING
  • RUNNABLE

最终总结

真正的 Java 高并发本质:

Linux内核 + epoll + Reactor + 线程池

Tomcat 本质:

Java版 Reactor 网络框架

Netty 本质:

更强大的 Reactor 框架

高并发核心:

减少线程
减少阻塞
减少拷贝
减少上下文切换

真正深入 Java 网络底层后,你会发现:

高级框架只是Linux网络模型的封装。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐