【Java 网络编程入门】计算机网络核心概念解析:从 IP 到 TCP/UDP 协议
前言
在 Java 开发中,网络编程是构建分布式系统、微服务架构的核心基础。本文将结合廖雪峰 Java 教程中的「网络编程基础」内容,系统梳理计算机网络的核心概念。
一、计算机网络与互联网:从局域网到全球网络
1. 计算机网络的本质
- 定义:两台或多台计算机通过统一协议组成的通信网络,同一网络内设备可直接通信
- 核心要素:统一的网络协议(如 TCP/IP)是通信基础
2. 互联网(Internet)的本质
- 定义:"网络的网络",通过 TCP/IP 协议将全球计算机网络互联
- 关键特性:唯一识别:通过 IP 地址唯一标识设备;跨网通信:通过路由器等设备实现不同网络互联
二、IP 地址:网络设备的 "门牌号"
1. IP 地址的分类与结构
(1)按版本分类
- IPv4:32 位地址(如
101.202.99.12),采用点分十进制表示,总数约 42 亿(已耗尽) - IPv6:128 位地址(如
2001:0DA8:100A:0000:0000:1020:F2F3:1428),总数达 3.4×10³⁸个
(2)按访问范围分类
- 公网 IP:可直接被互联网访问(如服务器地址)
- 内网 IP:仅限局域网访问(常见段:
192.168.x.x、10.x.x.x) - 特殊地址:本机地址
127.0.0.1(回环地址,用于本地测试)
2. 网络通信的核心逻辑:网络号计算
IP地址 : 101.202.99.2
子网掩码 : 255.255.255.0
网络号计算 : IP & 子网掩码 = 101.202.99.0
- 判断依据:两台设备网络号相同则属于同一局域网,可直接通信;否则需通过网关(路由器)转发
3. 网卡的三要素配置
graph LR
A[IP地址] --> B[子网掩码]
A --> C[网关IP]
三、域名系统(DNS):人类友好的地址翻译器
1. 核心作用
- 将难记忆的 IP 地址映射为易读的域名(如
liaoxuefeng.com→xxx.xxx.xxx.xxx)
2. 实用工具:nslookup 命令
# 命令示例
nslookup liaoxuefeng.com
# 输出示例
Server: xxx.xxx.xxx.xxx
Address: xxx.xxx.xxx.xxx#53
Non-authoritative answer:
Name: liaoxuefeng.com
Address: xxx.xxx.xxx.xxx
3. 特殊域名:localhost
- 永远指向本机地址
127.0.0.1,用于本地开发测试
四、网络模型:从理论到实践的分层架构
1. OSI 七层模型(理论标准)
| 层级 | 核心功能 | 典型技术 |
|---|---|---|
| 应用层 | 应用程序间通信(如 HTTP、FTP) | REST API、邮件协议 |
| 表示层 | 数据格式转换、加密解密 | JSON/XML 解析、SSL/TLS |
| 会话层 | 建立 / 维护会话状态 | 会话保持(Session) |
| 传输层 | 端到端可靠传输(TCP)/ 非可靠传输(UDP) | TCP/UDP 协议 |
| 网络层 | 路由选择与 IP 寻址 | IP 协议、路由算法 |
| 链路层 | 数据帧封装与物理链路传输 | Ethernet、Wi-Fi 协议 |
| 物理层 | 二进制比特流传输(硬件层面) | 光纤、双绞线 |
2. TCP/IP 五层模型(实际应用)
应用层(HTTP、DNS等)
├─ 传输层(TCP、UDP)
├─ IP层(IP协议)
└─ 网络接口层(链路层+物理层)
五、核心传输协议:TCP vs UDP
1. TCP 协议:可靠的 "快递员"
(1)关键特性
- 面向连接:通信前需 "三次握手" 建立连接,传输完毕 "四次挥手" 断开连接
- 可靠传输:通过确认机制、超时重传、流量控制保证数据完整性
- 双向通信:支持全双工通信(如 HTTP、WebSocket)
(2)典型应用场景
- 需要数据准确性的场景:文件传输、数据库连接、HTTP 请求
2. UDP 协议:高效的 "信使"
(1)关键特性
- 无连接:无需提前建立连接,直接发送数据报
- 不可靠传输:不保证顺序和到达,可能丢包
- 轻量级:协议简单,传输效率高
(2)典型应用场景
- 对实时性要求高、容忍丢包的场景:语音通话(VoIP)、视频直播、DNS 查询
六、开发者必备知识图谱
graph TD
A[网络编程基础] --> B(IP地址与子网划分)
A --> C(域名解析与DNS)
A --> D(OSI/TCP-IP模型)
A --> E{传输协议选择}
E -->|可靠传输| TCP((TCP协议))
E -->|高效传输| UDP((UDP协议))
Java TCP 编程全解析:从 Socket 原理到实战开发(附完整代码)
二、TCP 编程核心概念:Socket 与网络通信
2.1 Socket 原理
- 定义:Socket 是 IP 地址与端口号的组合(如
192.168.1.1:8080),用于唯一标识网络中的进程 - 作用:解决单一 IP 地址下多进程通信问题,通过端口号区分不同应用(如浏览器 80 端口、邮件客户端 25 端口)
- 端口范围:0-65535,其中 1024 以下为特权端口(需管理员权限)
┌───────────┐ ┌──────┐ ┌───────────┐
│Application│ │Router│ │Application│
├───────────┤◀──TCP──▶│Router│◀──IP───▶├───────────┤
│ Socket │ └──────┘ │ Socket │
└───────────┘ └───────────┘
2.2 通信模型
-
服务器端:监听固定端口,等待客户端连接(如 Web 服务器监听 80 端口)
-
客户端:主动连接服务器 IP + 端口,建立 TCP 连接后通信
-
核心流程:
- 服务器创建
ServerSocket绑定端口 - 客户端通过
Socket发起连接 - 双方通过
InputStream/OutputStream读写数据
- 服务器创建
三、服务器端实现:多线程处理并发连接
3.1 核心代码示例
import java.net.*;
import java.io.*;
public class TCPServer {
public static void main(String[] args) throws IOException {
// 1. 绑定端口6666
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("Server started, listening on port 6666...");
// 2. 循环处理客户端连接(多线程模式)
while (true) {
Socket clientSocket = serverSocket.accept(); // 阻塞等待连接
new Thread(() -> handleClient(clientSocket)).start();
}
}
private static void handleClient(Socket socket) {
try (
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
) {
// 3. 读写流处理
BufferedReader reader = new BufferedReader(
new InputStreamReader(is, StandardCharsets.UTF_8)
);
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(os, StandardCharsets.UTF_8), true
);
// 示例:回显客户端消息
String message;
while ((message = reader.readLine()) != null) {
if ("bye".equals(message)) break;
writer.println("Server received: " + message);
}
} catch (IOException e) {
System.out.println("Client disconnected: " + e.getMessage());
}
}
}
3.2 关键要点
- 多线程处理:每个客户端连接分配独立线程,避免阻塞主线程
- 资源管理:使用
try-with-resources自动释放 Socket 资源 - 端口占用:启动前确保端口未被占用(可通过
netstat -ano检查)
四、客户端实现:快速连接与数据交互
4.1 核心代码示例
import java.net.*;
import java.io.*;
public class TCPClient {
public static void main(String[] args) throws IOException {
// 1. 连接服务器(本地地址+端口6666)
try (Socket socket = new Socket("localhost", 6666)) {
// 2. 获取输入输出流
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream()), true
);
// 3. 发送消息并接收响应
Scanner scanner = new Scanner(System.in);
System.out.println("Enter message (type 'bye' to exit):");
while (scanner.hasNextLine()) {
String input = scanner.nextLine();
writer.println(input); // 自动flush
String response = reader.readLine();
System.out.println("Server response: " + response);
if ("bye".equals(input)) break;
}
} catch (IOException e) {
System.out.println("Connection failed: " + e.getMessage());
}
}
}
4.2 关键要点
- 连接超时:可通过
Socket(int port, InetAddress bindAddr)指定本地端口或超时时间 - 字符编码:确保客户端与服务器端编码一致(示例使用 UTF-8)
- flush 机制:
PrintWriter构造参数autoFlush=true可自动刷新缓冲区
五、Socket 流处理核心机制
5.1 流模型
-
输入流:
socket.getInputStream()获取网络输入,阻塞式读取 -
输出流:
socket.getOutputStream()写入网络数据,需手动调用flush()或使用自动刷新机制 -
缓冲区优化:
- 小数据量:使用
PrintWriter自动刷新 - 大数据量:手动控制
flush()减少 IO 次数
- 小数据量:使用
5.2 常见问题
- 粘包问题:TCP 是字节流协议,需通过边界符(如
\n)或长度字段处理分包 - 阻塞处理:多线程或 NIO(非阻塞 IO)模式处理高并发场景
🚀 Java UDP 编程实战:无连接通信的快速实现
导语
在网络编程中,UDP(用户数据报协议)以其无连接、简单高效的特性,成为实时通信、广播消息等场景的首选。
一、UDP 与 TCP 的核心区别
| 特性 | UDP | TCP |
|---|---|---|
| 连接方式 | 无连接(非面向连接) | 面向连接(需三次握手) |
| 可靠性 | 不可靠(无重传机制) | 可靠(保证顺序与完整性) |
| 传输单位 | 数据报(Datagram,最大 64KB) | 字节流(Stream) |
| 端口独立性 | 与 TCP 端口独立(可复用同一端口号) | 独占端口 |
| 典型场景 | 实时音视频、广播、DNS 查询 | 文件传输、HTTP 请求 |
二、服务器端实现:监听与响应
1. 核心类:DatagramSocket
通过DatagramSocket绑定端口,接收 / 发送DatagramPacket数据报。
try (DatagramSocket ds = new DatagramSocket(6666)) { // 监听端口6666
byte[] buffer = new byte[1024];
while (true) {
// 1. 接收数据报
DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
ds.receive(receivePacket); // 阻塞等待数据
// 2. 解析数据
String request = new String(
receivePacket.getData(),
receivePacket.getOffset(),
receivePacket.getLength(),
StandardCharsets.UTF_8
);
System.out.println("收到客户端消息:" + request);
// 3. 构造响应
String response = "ACK: " + request;
byte[] data = response.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(
data,
data.length,
receivePacket.getAddress(), // 客户端IP
receivePacket.getPort() // 客户端端口
);
ds.send(sendPacket); // 发送响应
}
} catch (IOException e) {
e.printStackTrace();
}
2. 关键步骤解析
- 数据报解析:通过
getOffset()和getLength()获取有效数据范围,避免缓冲区剩余数据干扰。 - 自动响应:从
DatagramPacket中提取客户端地址 / 端口,确保响应能准确回传。
三、客户端实现:主动发起与灵活通信
1. 基础通信流程
try (DatagramSocket ds = new DatagramSocket()) {
ds.setSoTimeout(1000); // 设置超时时间(毫秒)
InetAddress serverAddr = InetAddress.getByName("localhost");
// 1. 发送请求
String request = "Hello UDP!";
DatagramPacket sendPacket = new DatagramPacket(
request.getBytes(StandardCharsets.UTF_8),
request.length(),
serverAddr,
6666
);
ds.send(sendPacket);
// 2. 接收响应
byte[] buffer = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
ds.receive(receivePacket);
String response = new String(
receivePacket.getData(),
receivePacket.getOffset(),
receivePacket.getLength()
);
System.out.println("服务器响应:" + response);
} catch (IOException e) {
e.printStackTrace();
}
2. 灵活通信模式
模式 1:预连接指定服务器(推荐)
ds.connect(serverAddr, 6666); // 绑定目标地址,后续发送无需重复指定
ds.send(new DatagramPacket(data, data.length)); // 简化发送代码
模式 2:单 Socket 多目标通信
// 发送到不同服务器
ds.send(new DatagramPacket(data1, data1.length, addr1, port1));
ds.send(new DatagramPacket(data2, data2.length, addr2, port2));
四、核心注意事项
-
端口独立性:TCP 和 UDP 端口独立,如 TCP 占用 8080 端口,UDP 仍可使用 8080 端口。
-
无连接特性:
- 服务器无法主动向未通信的客户端发送数据,必须先接收客户端请求。
- 数据报可能丢失或乱序,需上层应用自行处理可靠性(如 ACK 确认)。
-
缓冲区限制:单个数据报最大 64KB(受 IP 协议限制),超出需手动分包。
五、适用场景与最佳实践
推荐场景
- 实时通信:视频会议、游戏状态同步(低延迟优先)。
- 广播 / 组播:设备发现(如 DHCP、mDNS)。
- 简单查询:DNS 请求、监控数据上报。
优化建议
- 设置超时:客户端通过
setSoTimeout()避免阻塞卡死。 - 数据压缩:传输大量数据时结合压缩算法(如 Snappy)减少包数量。
- 可靠性增强:自定义序列号 + ACK 机制实现 “伪可靠” 传输。
Java 实现邮件发送全攻略:从基础到高级应用
一、引言
在 Java 开发中,通过程序自动发送电子邮件是常见需求。
二、邮件发送核心原理
2.1 邮件传输流程
- MUA(邮件用户代理) :如 Outlook、Java 程序,负责生成邮件并发送到 MTA。
- MTA(邮件传输代理) :邮件中转服务器,通过 SMTP 协议传输邮件。
- MDA(邮件投递代理) :最终存储邮件的服务器,供用户接收。
2.2 SMTP 协议基础
-
协议作用:MUA 与 MTA 通信的标准协议,默认端口
25,加密端口465(SSL)或587(TLS)。 -
常用邮箱 SMTP 配置:
- QQ 邮箱:
smtp.qq.com,端口465/587 - 163 邮箱:
smtp.163.com,端口465 - Gmail:
smtp.gmail.com,端口465/587
- QQ 邮箱:
三、环境准备
3.1 Maven 依赖
<!-- JavaMail API -->
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
3.2 SMTP 登录信息
需准备:
- 邮箱地址(如
me@example.com) - SMTP 服务器地址(如
smtp.qq.com) - 登录口令(通常为邮箱密码或独立 SMTP 授权码)
四、基础邮件发送
4.1 发送纯文本邮件
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class EmailSender {
public static void sendTextEmail() throws MessagingException {
// 配置SMTP
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.office365.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
// 创建Session
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user@example.com", "password");
}
});
session.setDebug(true); // 开启调试模式
// 构造邮件
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("sender@example.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("receiver@example.com"));
message.setSubject("Hello from Java", "UTF-8");
message.setText("这是一封纯文本邮件", "UTF-8");
// 发送邮件
Transport.send(message);
}
}
4.2 发送 HTML 邮件
只需修改正文内容为 HTML 格式:
message.setText("<h1>HTML邮件</h1><p>这是一段HTML内容</p>", "UTF-8", "html");
五、高级功能实现
5.1 发送带附件的邮件
使用Multipart组合正文和附件:
public static void sendAttachmentEmail() throws MessagingException, IOException {
// 创建Multipart对象
Multipart multipart = new MimeMultipart();
// 添加正文(HTML格式)
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent("<p>邮件正文</p>", "text/html;charset=utf-8");
multipart.addBodyPart(textPart);
// 添加附件(图片)
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.setFileName("image.jpg");
imagePart.setDataHandler(new DataHandler(new ByteArrayDataSource(
new FileInputStream("path/to/image.jpg"), "image/jpeg")));
multipart.addBodyPart(imagePart);
// 设置邮件内容
message.setContent(multipart);
}
5.2 内嵌图片的 HTML 邮件
通过Content-ID关联 HTML 中的图片引用:
// HTML正文引用图片
textPart.setContent("<p><img src="cid:img01"></p>", "text/html;charset=utf-8");
// 图片BodyPart设置Content-ID
imagePart.setHeader("Content-ID", "<img01>");
六、常见问题与解决方案
6.1 登录失败(错误码 535)
-
原因:用户名 / 密码错误或未启用 SMTP 服务。
-
解决:
- 检查邮箱是否开启 SMTP(如 QQ 邮箱需生成授权码)。
- 使用授权码而非邮箱密码登录。
6.2 端口错误
- SSL 加密:使用端口
465,配置mail.smtp.ssl.enable=true。 - TLS 加密:使用端口
587,配置mail.smtp.starttls.enable=true。
6.3 邮件被识别为垃圾邮件
-
解决:
- 避免主题 / 正文过于简单(如仅 “测试”)。
- 添加合理内容或使用 DKIM/SPF 认证。
Java HTTP 编程全解析:从协议基础到 HttpClient 实战
一、HTTP 协议核心概念速览
1. 协议本质与应用场景
- 定义:超文本传输协议(HyperText Transfer Protocol),基于 TCP 的请求 - 响应式应用层协议
- 典型场景:浏览器访问网站、App 与服务器通信、接口调用等
- 端口:默认 80(明文)/443(加密 HTTPS)
2. 请求与响应结构
请求格式(以 POST 为例)
POST /login HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=hello&password=123456
- **请求行**:方法 + 路径 + 版本(如`GET / HTTP/1.1`)
- **请求头**:Host、User-Agent、Content-Type 等关键字段
- **请求体**:POST/PUT 等方法携带数据,GET 通过 URL 参数传递
响应格式
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 133251
<!DOCTYPE html><body><h1>Hello</h1></body></html>
-
状态行:版本 + 状态码 + 原因短语(如
200 OK) -
状态码分类:
- 2xx(成功):200 OK、206 Partial Content
- 3xx(重定向):301 永久重定向、303 查看其他位置
- 4xx(客户端错误):404 Not Found、400 Bad Request
- 5xx(服务器错误):500 Internal Server Error
3. 协议版本演进
| 特性 | HTTP/1.1 | HTTP/2.0 |
|---|---|---|
| 连接复用 | 支持长连接 | 多路复用(单个连接并发请求) |
| 头部压缩 | 无 | 采用 HPACK 压缩 |
| 请求优先级 | 无 | 支持请求优先级设置 |
| 服务器推送 | 无 | 支持主动推送资源 |
二、Java HTTP 客户端编程实践
1. 新旧 API 对比
| 特性 | HttpURLConnection(旧) | HttpClient(Java 11 + 新) |
|---|---|---|
| 编程模型 | 繁琐的连接管理 | 链式调用 + 流式处理 |
| 异步支持 | 需手动实现 | 内置sendAsync异步方法 |
| 响应体处理 | 手动读取 InputStream | 内置BodyHandlers处理器 |
| 连接池管理 | 需手动配置 | 自动管理连接池 |
2. HttpClient 核心用法
步骤 1:创建客户端实例
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) // 指定协议版本
.connectTimeout(Duration.ofSeconds(5)) // 连接超时
.build();
步骤 2:构建请求
GET 请求(获取文本)
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.sina.com.cn/"))
.header("User-Agent", "Java HttpClient")
.GET() // 可选,默认GET
.build();
POST 请求(发送表单数据)
String body = "username=bob&password=123456";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://www.example.com/login"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(BodyPublishers.ofString(body)) // 发送字符串体
.build();
POST 请求(发送 JSON 数据)
Map<String, String> jsonBody = Map.of("username", "alice", "password", "secure");
String json = new ObjectMapper().writeValueAsString(jsonBody);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://api.example.com/auth"))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(json, StandardCharsets.UTF_8))
.build();
步骤 3:发送请求并处理响应
同步处理(阻塞式)
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString()); // 响应体转为字符串
System.out.println("状态码:" + response.statusCode());
response.headers().map().forEach((k, v) ->
System.out.println(k + ": " + v.get(0))); // 打印首部
System.out.println("响应体:" + response.body().substring(0, 100));
异步处理(非阻塞式)
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request,
HttpResponse.BodyHandlers.ofString());
future.thenApply(HttpResponse::body)
.thenAccept(body -> System.out.println("异步响应体:" + body));
高级用法:处理二进制数据
// 获取图片字节数组
HttpResponse<byte[]> imageResponse = client.send(request,
HttpResponse.BodyHandlers.ofByteArray());
byte[] imageData = imageResponse.body();
// 流式处理大文件(避免内存溢出)
HttpResponse<InputStream> streamResponse = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try (InputStream is = streamResponse.body()) {
// 流式读取处理
}
三、最佳实践与注意事项
-
连接管理:
- 全局共享
HttpClient实例(内部维护连接池) - 避免每次请求创建新客户端
- 全局共享
-
请求优化:
- 优先使用 HTTP/2(需服务器支持)
- 合理设置超时(
connectTimeout+responseTimeout)
-
安全处理:
- 敏感数据使用 HTTPS
- 自定义
SSLContext实现证书校验
-
错误处理:
- 捕获
IOException和InterruptedException - 通过状态码(
response.statusCode())判断请求结果
- 捕获
Java RMI 远程调用详解
核心要点
1. RMI 基础概念
-
定义:允许一个 JVM 通过网络调用另一个 JVM 的方法,基于接口实现。
-
角色:
- 服务器:提供服务实现,注册服务到 RMI 注册表(默认端口 1099)。
- 客户端:通过接口引用远程服务,透明调用方法。
2. 实现步骤
定义共享接口
public interface WorldClock extends Remote {
LocalDateTime getLocalDateTime(String zoneId) throws RemoteException;
}
- 要求:接口必须继承
Remote,方法声明RemoteException。
服务端实现
public class WorldClockService implements WorldClock {
@Override
public LocalDateTime getLocalDateTime(String zoneId) throws RemoteException {
return LocalDateTime.now(ZoneId.of(zoneId)).withNano(0);
}
}
-
注册服务:
WorldClock skeleton = (WorldClock) UnicastRemoteObject.exportObject(worldClock, 0); Registry registry = LocateRegistry.createRegistry(1099); registry.rebind("WorldClock", skeleton);exportObject:将服务导出为远程对象,端口0表示自动分配。createRegistry:创建 RMI 注册表,绑定端口。
客户端调用
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
WorldClock worldClock = (WorldClock) registry.lookup("WorldClock");
LocalDateTime now = worldClock.getLocalDateTime("Asia/Shanghai");
- 通过
lookup获取远程接口引用,直接调用方法。
3. 核心原理
-
动态代理机制:
- Stub:客户端代理,负责将方法调用转为网络请求。
- Skeleton:服务端代理,接收请求并调用实际服务实现。
-
序列化依赖:参数和返回值需可序列化,存在安全风险(如反序列化漏洞)。
4. 安全与限制
- 安全隐患:序列化机制可能引入代码执行漏洞,需确保调用方可信,禁止公网暴露 1099 端口。
- 语言限制:仅限 Java 生态,跨语言场景推荐使用 gRPC(基于 HTTP/2,支持多语言)。
5. 与 gRPC 对比
| 维度 | RMI | gRPC |
|---|---|---|
| 协议 | 私有协议 | HTTP/2 |
| 序列化 | Java 序列化 | Protobuf |
| 跨语言 | 仅限 Java | 多语言(Java/Go/Python 等) |
| 性能 | 依赖 Java 序列化效率 | 更高(二进制 + 压缩) |