java-网络编程

【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.x10.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 连接后通信

  • 核心流程

    1. 服务器创建ServerSocket绑定端口
    2. 客户端通过Socket发起连接
    3. 双方通过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 的核心区别

特性UDPTCP
连接方式无连接(非面向连接)面向连接(需三次握手)
可靠性不可靠(无重传机制)可靠(保证顺序与完整性)
传输单位数据报(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));

四、核心注意事项

  1. 端口独立性:TCP 和 UDP 端口独立,如 TCP 占用 8080 端口,UDP 仍可使用 8080 端口。

  2. 无连接特性

    • 服务器无法主动向未通信的客户端发送数据,必须先接收客户端请求。
    • 数据报可能丢失或乱序,需上层应用自行处理可靠性(如 ACK 确认)。
  3. 缓冲区限制:单个数据报最大 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

三、环境准备

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.1HTTP/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()) {
    // 流式读取处理
}

三、最佳实践与注意事项

  1. 连接管理

    • 全局共享HttpClient实例(内部维护连接池)
    • 避免每次请求创建新客户端
  2. 请求优化

    • 优先使用 HTTP/2(需服务器支持)
    • 合理设置超时(connectTimeout+responseTimeout
  3. 安全处理

    • 敏感数据使用 HTTPS
    • 自定义SSLContext实现证书校验
  4. 错误处理

    • 捕获IOExceptionInterruptedException
    • 通过状态码(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 对比

维度RMIgRPC
协议私有协议HTTP/2
序列化Java 序列化Protobuf
跨语言仅限 Java多语言(Java/Go/Python 等)
性能依赖 Java 序列化效率更高(二进制 + 压缩)