十四、网络编程

5 阅读10分钟

Java 网络编程


网络编程核心基础

核心常识

  • IP:定位一台主机
  • Port:定位主机上的一个应用(0~65535)
  • 协议:通信规则(TCP、UDP、HTTP、HTTPS)
  • OSI 七层 / TCP/IP 四层模型

TCP/IP 四层模型

  1. 应用层(HTTP、FTP、DNS)
  2. 传输层(TCP、UDP)
  3. 网络层(IP)
  4. 网络接口层(硬件)

通信本质

两台主机通过 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(通道,双向)

  • FileChannel
  • SocketChannel(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 流程极简版

  1. 注册 Channel 到 Selector
  2. Selector 阻塞监听事件
  3. 有事件 → 处理对应 Channel
  4. 非阻塞,高性能

9. 网络编程高频问题(企业真实坑)

坑1:TCP 粘包 / 拆包(最经典)

  • 原因:TCP 是流协议,无消息边界
  • 现象:多条消息粘在一起 / 一条消息被拆开
  • 解决方案:
    1. 固定长度
    2. 分隔符(\n、特殊符号)
    3. 消息头+消息体(长度字段)【企业标准】

坑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% 考)

  1. TCP 和 UDP 区别与使用场景?
  2. TCP 三次握手、四次挥手(必问)
  3. 什么是粘包拆包?怎么解决?
  4. BIO vs NIO vs AIO 区别?
  5. NIO 三大组件 Buffer/Channel/Selector 作用?
  6. Socket 编程中 read() 什么时候返回 -1?
  7. 如何实现一个高并发服务端?
  8. 为什么不建议使用 Java 原生序列化?
  9. 心跳机制作用是什么?
  10. 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 四层模型

  1. 应用层(HTTP、FTP、DNS)
  2. 传输层(TCP、UDP)
  3. 网络层(IP)
  4. 网络接口层(硬件)

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(通道,双向)

  • FileChannel
  • SocketChannel(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 流程极简版

  1. 注册 Channel 到 Selector
  2. Selector 阻塞监听事件
  3. 有事件 → 处理对应 Channel
  4. 非阻塞,高性能

9. 网络编程高频问题(企业真实坑)

坑1:TCP 粘包 / 拆包(最经典)

  • 原因:TCP 是流协议,无消息边界
  • 现象:多条消息粘在一起 / 一条消息被拆开
  • 解决方案:
    1. 固定长度
    2. 分隔符(\n、特殊符号)
    3. 消息头+消息体(长度字段)【企业标准】

坑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% 考)

  1. TCP 和 UDP 区别与使用场景?
  2. TCP 三次握手、四次挥手(必问)
  3. 什么是粘包拆包?怎么解决?
  4. BIO vs NIO vs AIO 区别?
  5. NIO 三大组件 Buffer/Channel/Selector 作用?
  6. Socket 编程中 read() 什么时候返回 -1?
  7. 如何实现一个高并发服务端?
  8. 为什么不建议使用 Java 原生序列化?
  9. 心跳机制作用是什么?
  10. Netty 解决了什么问题?