Java 网络编程
网络编程核心基础
核心常识
- IP:定位一台主机
- Port:定位主机上的一个应用(0~65535)
- 协议:通信规则(TCP、UDP、HTTP、HTTPS)
- OSI 七层 / TCP/IP 四层模型
TCP/IP 四层模型
- 应用层(HTTP、FTP、DNS)
- 传输层(TCP、UDP)
- 网络层(IP)
- 网络接口层(硬件)
通信本质
两台主机通过 IO 流交换数据 Java 网络编程 = Socket + IO
1. 核心类与地址相关
1.1 InetAddress(IP 地址封装)
// 获取本机
InetAddress localHost = InetAddress.getLocalHost();
// 根据域名获取
InetAddress address = InetAddress.getByName("www.baidu.com");
address.getHostName(); // 主机名
address.getHostAddress();// IP
address.isReachable(3000); // 是否可达
1.2 端口
- 0~1023:知名端口(HTTP:80、HTTPS:443、FTP:21、DNS:53)
- 1024~65535:自定义端口
2. 传输层两大协议:TCP vs UDP
2.1 TCP(传输控制协议)
- 面向连接
- 可靠传输(确认、重传、有序)
- 字节流传输
- 慢,开销大
- 场景:浏览器、文件传输、IM、支付
2.2 UDP(用户数据报协议)
- 无连接
- 不可靠,可能丢包、乱序
- 数据报模式
- 快,开销小
- 场景:直播、视频通话、游戏、DNS
3. TCP 编程(基于 Socket)
3.1 模型
- ServerSocket:服务端,监听端口,等待连接
- Socket:客户端,发起连接 连接成功后双方各获得 InputStream + OutputStream
3.2 服务端(单线程版本)
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("等待连接...");
Socket socket = serverSocket.accept(); // 阻塞,直到客户端连接
// 获取流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// 读写数据
byte[] buf = new byte[1024];
int len = in.read(buf);
String msg = new String(buf, 0, len);
socket.close();
serverSocket.close();
3.3 客户端
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream out = socket.getOutputStream();
out.write("Hello TCP".getBytes());
socket.close();
3.4 TCP 特点
accept()阻塞read()阻塞- 长连接,双向通信
4. 多线程 TCP 服务端(企业基础模型)
一个连接一个线程:
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> {
// 处理该 socket 读写
}).start();
}
问题:连接多时线程爆炸,OOM,频繁切换
5. UDP 编程(基于 DatagramSocket)
5.1 核心类
DatagramSocket:发送/接收包裹DatagramPacket:数据报(包裹)
5.2 接收端(先启动)
DatagramSocket socket = new DatagramSocket(9999);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet); // 阻塞
String msg = new String(packet.getData(), 0, packet.getLength());
socket.close();
5.3 发送端
DatagramSocket socket = new DatagramSocket();
byte[] data = "Hello UDP".getBytes();
DatagramPacket packet = new DatagramPacket(
data, data.length,
InetAddress.getByName("127.0.0.1"), 9999
);
socket.send(packet);
socket.close();
5.4 UDP 特点
- 不保证到达
- 不保证顺序
- 无连接
- 不阻塞(除 receive)
6. URL 与 HTTP 编程(应用层最常用)
6.1 URL 类
URL url = new URL("http://www.baidu.com");
InputStream in = url.openStream();
// 读取网页内容
6.2 HttpURLConnection(原生 HTTP 客户端)
URL url = new URL("http://xxx.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
conn.connect();
if (conn.getResponseCode() == 200) {
InputStream in = conn.getInputStream();
}
conn.disconnect();
6.3 真实企业不用原生
- 易用性差
- 无连接池
- 异常繁琐 实际使用:OkHttp、HttpClient、RestTemplate、Feign
7. BIO、NIO、AIO 三种 IO 模型(超级重点)
7.1 BIO(Blocking IO)
- 阻塞 IO
- 一连接一线程
- 并发低,高并发不可用
- 简单,适合连接极少的场景
7.2 NIO(Non-blocking IO / New IO)
- 非阻塞 + 多路复用
- 一个线程处理多个连接(Selector)
- 基于 Channel + Buffer + Selector
- 高并发、低资源
- Netty 底层就是 NIO
7.3 AIO(Asynchronous IO)
- 异步非阻塞
- 操作系统完成后回调
- Windows 支持好,Linux 一般
- 普及度远不如 NIO
8. Java NIO 三大核心(面试必考)
8.1 Channel(通道,双向)
FileChannelSocketChannel(TCP 客户端)ServerSocketChannel(TCP 服务端)DatagramChannel(UDP)
8.2 Buffer(缓冲区)
- 本质数组
- 核心属性:
position / limit / capacity - 必须
flip()切换读写模式
8.3 Selector(多路复用器)
- 一个线程监听多个 Channel 事件
- 事件:
- OP_ACCEPT 连接
- OP_CONNECT 连接就绪
- OP_READ 读
- OP_WRITE 写
NIO 流程极简版
- 注册 Channel 到 Selector
- Selector 阻塞监听事件
- 有事件 → 处理对应 Channel
- 非阻塞,高性能
9. 网络编程高频问题(企业真实坑)
坑1:TCP 粘包 / 拆包(最经典)
- 原因:TCP 是流协议,无消息边界
- 现象:多条消息粘在一起 / 一条消息被拆开
- 解决方案:
- 固定长度
- 分隔符(\n、特殊符号)
- 消息头+消息体(长度字段)【企业标准】
坑2:Socket 资源未关闭 → 文件句柄泄漏
- 服务器 Too many open files
- 必须
try-with-resources
坑3:read() 阻塞导致程序假死
- 对方不发数据也不断开
- 解决方案:设置超时
socket.setSoTimeout(ms)
坑4:TCP 半关闭问题
- 一方 close,另一方还在 write
- 触发:
Broken pipe/Connection reset
坑5:UDP 丢包、乱序
- 不能用于支付、订单等可靠场景
坑6:端口被占用
- Address already in use
- 杀进程或换端口
坑7:编码不一致导致乱码
- 读写必须指定
UTF-8
坑8:BIO 线程过多导致 OOM、CPU 飙升
- 高并发必须 NIO 或线程池控制
坑9:长连接心跳缺失
- 网络中断后双方不知道
- 需心跳包(heartbeat)
坑10:序列化效率低、不安全
- Java 序列化:慢、有漏洞
- 企业用:Protobuf、JSON、Kryo
10. 企业主流网络框架:Netty
为什么要用 Netty
- 封装 NIO,API 简单
- 解决粘包拆包
- 内置编解码器
- 高性能、高并发
- 心跳、重连、流量整形
- 广泛用于:RPC、游戏、消息队列、网关
Netty 核心模型
- Reactor 主从多线程模型
- Boss 组:接收连接
- Worker 组:处理 IO
11. 高频面试题(100% 考)
- TCP 和 UDP 区别与使用场景?
- TCP 三次握手、四次挥手(必问)
- 什么是粘包拆包?怎么解决?
- BIO vs NIO vs AIO 区别?
- NIO 三大组件 Buffer/Channel/Selector 作用?
- Socket 编程中 read() 什么时候返回 -1?
- 如何实现一个高并发服务端?
- 为什么不建议使用 Java 原生序列化?
- 心跳机制作用是什么?
- Netty 解决了什么问题?
下一份继续按这个极度详细风格整理
你接下来要:
Java JVM 虚拟机(内存模型 + GC + 类加载 + JVM 参数 + 调优 + 线上问题)
直接说 继续,我立刻给你拉满全套笔记!# Java 网络编程 极度详细完整版 (严格延续超详细风格:模型 + Socket + TCP + UDP + NIO + 粘包拆包 + HTTP + 常见坑 + 面试全覆盖)
0. 网络编程核心基础
0.1 核心常识
- IP:定位一台主机
- Port:定位主机上的一个应用(0~65535)
- 协议:通信规则(TCP、UDP、HTTP、HTTPS)
- OSI 七层 / TCP/IP 四层模型
0.2 TCP/IP 四层模型
- 应用层(HTTP、FTP、DNS)
- 传输层(TCP、UDP)
- 网络层(IP)
- 网络接口层(硬件)
0.3 通信本质
两台主机通过 IO 流交换数据 Java 网络编程 = Socket + IO
1. 核心类与地址相关
1.1 InetAddress(IP 地址封装)
// 获取本机
InetAddress localHost = InetAddress.getLocalHost();
// 根据域名获取
InetAddress address = InetAddress.getByName("www.baidu.com");
address.getHostName(); // 主机名
address.getHostAddress();// IP
address.isReachable(3000); // 是否可达
1.2 端口
- 0~1023:知名端口(HTTP:80、HTTPS:443、FTP:21、DNS:53)
- 1024~65535:自定义端口
2. 传输层两大协议:TCP vs UDP
2.1 TCP(传输控制协议)
- 面向连接
- 可靠传输(确认、重传、有序)
- 字节流传输
- 慢,开销大
- 场景:浏览器、文件传输、IM、支付
2.2 UDP(用户数据报协议)
- 无连接
- 不可靠,可能丢包、乱序
- 数据报模式
- 快,开销小
- 场景:直播、视频通话、游戏、DNS
3. TCP 编程(基于 Socket)
3.1 模型
- ServerSocket:服务端,监听端口,等待连接
- Socket:客户端,发起连接 连接成功后双方各获得 InputStream + OutputStream
3.2 服务端(单线程版本)
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("等待连接...");
Socket socket = serverSocket.accept(); // 阻塞,直到客户端连接
// 获取流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// 读写数据
byte[] buf = new byte[1024];
int len = in.read(buf);
String msg = new String(buf, 0, len);
socket.close();
serverSocket.close();
3.3 客户端
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream out = socket.getOutputStream();
out.write("Hello TCP".getBytes());
socket.close();
3.4 TCP 特点
accept()阻塞read()阻塞- 长连接,双向通信
4. 多线程 TCP 服务端(企业基础模型)
一个连接一个线程:
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> {
// 处理该 socket 读写
}).start();
}
问题:连接多时线程爆炸,OOM,频繁切换
5. UDP 编程(基于 DatagramSocket)
5.1 核心类
DatagramSocket:发送/接收包裹DatagramPacket:数据报(包裹)
5.2 接收端(先启动)
DatagramSocket socket = new DatagramSocket(9999);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet); // 阻塞
String msg = new String(packet.getData(), 0, packet.getLength());
socket.close();
5.3 发送端
DatagramSocket socket = new DatagramSocket();
byte[] data = "Hello UDP".getBytes();
DatagramPacket packet = new DatagramPacket(
data, data.length,
InetAddress.getByName("127.0.0.1"), 9999
);
socket.send(packet);
socket.close();
5.4 UDP 特点
- 不保证到达
- 不保证顺序
- 无连接
- 不阻塞(除 receive)
6. URL 与 HTTP 编程(应用层最常用)
6.1 URL 类
URL url = new URL("http://www.baidu.com");
InputStream in = url.openStream();
// 读取网页内容
6.2 HttpURLConnection(原生 HTTP 客户端)
URL url = new URL("http://xxx.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
conn.connect();
if (conn.getResponseCode() == 200) {
InputStream in = conn.getInputStream();
}
conn.disconnect();
6.3 真实企业不用原生
- 易用性差
- 无连接池
- 异常繁琐 实际使用:OkHttp、HttpClient、RestTemplate、Feign
7. BIO、NIO、AIO 三种 IO 模型(超级重点)
7.1 BIO(Blocking IO)
- 阻塞 IO
- 一连接一线程
- 并发低,高并发不可用
- 简单,适合连接极少的场景
7.2 NIO(Non-blocking IO / New IO)
- 非阻塞 + 多路复用
- 一个线程处理多个连接(Selector)
- 基于 Channel + Buffer + Selector
- 高并发、低资源
- Netty 底层就是 NIO
7.3 AIO(Asynchronous IO)
- 异步非阻塞
- 操作系统完成后回调
- Windows 支持好,Linux 一般
- 普及度远不如 NIO
8. Java NIO 三大核心(面试必考)
8.1 Channel(通道,双向)
FileChannelSocketChannel(TCP 客户端)ServerSocketChannel(TCP 服务端)DatagramChannel(UDP)
8.2 Buffer(缓冲区)
- 本质数组
- 核心属性:
position / limit / capacity - 必须
flip()切换读写模式
8.3 Selector(多路复用器)
- 一个线程监听多个 Channel 事件
- 事件:
- OP_ACCEPT 连接
- OP_CONNECT 连接就绪
- OP_READ 读
- OP_WRITE 写
NIO 流程极简版
- 注册 Channel 到 Selector
- Selector 阻塞监听事件
- 有事件 → 处理对应 Channel
- 非阻塞,高性能
9. 网络编程高频问题(企业真实坑)
坑1:TCP 粘包 / 拆包(最经典)
- 原因:TCP 是流协议,无消息边界
- 现象:多条消息粘在一起 / 一条消息被拆开
- 解决方案:
- 固定长度
- 分隔符(\n、特殊符号)
- 消息头+消息体(长度字段)【企业标准】
坑2:Socket 资源未关闭 → 文件句柄泄漏
- 服务器 Too many open files
- 必须
try-with-resources
坑3:read() 阻塞导致程序假死
- 对方不发数据也不断开
- 解决方案:设置超时
socket.setSoTimeout(ms)
坑4:TCP 半关闭问题
- 一方 close,另一方还在 write
- 触发:
Broken pipe/Connection reset
坑5:UDP 丢包、乱序
- 不能用于支付、订单等可靠场景
坑6:端口被占用
- Address already in use
- 杀进程或换端口
坑7:编码不一致导致乱码
- 读写必须指定
UTF-8
坑8:BIO 线程过多导致 OOM、CPU 飙升
- 高并发必须 NIO 或线程池控制
坑9:长连接心跳缺失
- 网络中断后双方不知道
- 需心跳包(heartbeat)
坑10:序列化效率低、不安全
- Java 序列化:慢、有漏洞
- 企业用:Protobuf、JSON、Kryo
10. 企业主流网络框架:Netty
为什么要用 Netty
- 封装 NIO,API 简单
- 解决粘包拆包
- 内置编解码器
- 高性能、高并发
- 心跳、重连、流量整形
- 广泛用于:RPC、游戏、消息队列、网关
Netty 核心模型
- Reactor 主从多线程模型
- Boss 组:接收连接
- Worker 组:处理 IO
11. 高频面试题(100% 考)
- TCP 和 UDP 区别与使用场景?
- TCP 三次握手、四次挥手(必问)
- 什么是粘包拆包?怎么解决?
- BIO vs NIO vs AIO 区别?
- NIO 三大组件 Buffer/Channel/Selector 作用?
- Socket 编程中 read() 什么时候返回 -1?
- 如何实现一个高并发服务端?
- 为什么不建议使用 Java 原生序列化?
- 心跳机制作用是什么?
- Netty 解决了什么问题?