通过rmi实现远程rpc(可以认为java自带Dubbo RPC)

背景:

发现公司几个运行10年的游戏,用的竟然是rmi,而我只听说过dubbo 和 基于netty的rpc,于是就补充了下rmi。

其次,是最近对于跨服的思考,如何避免回调也需要用同步写法,rmi比较适合。

1)api

游戏服之间的交互 // 必须抛出RemoteException异常

复制代码
package com.example.testsb.testrmi.api;

import com.example.testsb.testrmi.common.CSLogin;
import com.example.testsb.testrmi.common.SCLogin;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface IGameService extends Remote {
    // 简单的rpc接口
    String hello(String str) throws RemoteException;

    // 请求和返回都是复杂对象的rpc接口
    SCLogin login(CSLogin req) throws RemoteException;
}

2)通用部分

复制代码
package com.example.testsb.testrmi.common;

public class Constant {
    public final static int GAME_SERVICE_PORT = 6000;
    public final static String GAME_SERVICE_URL = String.format("rmi://localhost:%d/IGameService", GAME_SERVICE_PORT);
}

复杂协议 // 必须实现:Serializable接口

复制代码
package com.example.testsb.testrmi.common;

import lombok.Data;

import java.io.Serializable;

@Data
public class CSLogin implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private String password;
}

package com.example.testsb.testrmi.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SCLogin implements Serializable {
    private static final long serialVersionUID = 1L;

    private long uid;
}

3)服务端

复制代码
package com.example.testsb.testrmi.server;

import com.example.testsb.testrmi.api.IGameService;
import com.example.testsb.testrmi.common.Constant;
import com.example.testsb.testrmi.server.impl.GameServiceImpl;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

public class Server {
    public static void main(String[] args) throws RemoteException, MalformedURLException {
        IGameService gameService = new GameServiceImpl();
        LocateRegistry.createRegistry(Constant.GAME_SERVICE_PORT);
        Naming.rebind(Constant.GAME_SERVICE_URL, gameService);
    }
}

/*
[2024-03-19 07:14:13.601] [RMI TCP Connection(4)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:13.602] [RMI TCP Connection(4)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:13.603] [RMI TCP Connection(4)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:13.604] [RMI TCP Connection(4)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.975] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.982] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.984] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.986] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.988] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.993] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.995] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:29.997] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:30.000] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
[2024-03-19 07:14:30.002] [RMI TCP Connection(6)-192.168.152.1] [GameServiceImpl.java:24] ([INFO][com.example.testsb.testrmi.server.impl.GameServiceImpl] 1000 123
 */

实现

复制代码
package com.example.testsb.testrmi.server.impl;

import com.example.testsb.testrmi.api.IGameService;
import com.example.testsb.testrmi.common.CSLogin;
import com.example.testsb.testrmi.common.SCLogin;
import lombok.extern.slf4j.Slf4j;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

@Slf4j
public class GameServiceImpl extends UnicastRemoteObject implements IGameService {
    public GameServiceImpl() throws RemoteException {
        super();
    }

    @Override
    public String hello(String str) {
        return str + "_world";
    }

    @Override
    public SCLogin login(CSLogin req) {
        log.info("{} {}", req.getName().length(), req.getPassword());
        return new SCLogin(1);
    }
}

4)客户端

复制代码
package com.example.testsb.testrmi.client;

import com.example.testsb.testrmi.api.IGameService;
import com.example.testsb.testrmi.common.CSLogin;
import com.example.testsb.testrmi.common.Constant;
import com.example.testsb.testrmi.common.SCLogin;
import lombok.extern.slf4j.Slf4j;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

@Slf4j
public class Client {
    public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {
        IGameService gameService = (IGameService) Naming.lookup(Constant.GAME_SERVICE_URL);

        String name = "";
        for (int i = 0; i < 100; i++) {
            name += "123456789a";
        }

        for (int j = 0; j < 10; j++) {
            // 测试hello
            String hello = gameService.hello("hello");
            log.info("{}", hello);

            // 测试登录接口
            CSLogin csLogin = new CSLogin();
            csLogin.setName(name);
            csLogin.setPassword("123");

            SCLogin login = gameService.login(csLogin);
            log.info("{}", login);
        }
    }
}

/*
[2024-03-19 07:14:29.970] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.977] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.981] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.982] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.983] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.984] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.985] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.986] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.987] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.988] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.993] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.994] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.995] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.996] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.997] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:29.998] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:29.999] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:30.000] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
[2024-03-19 07:14:30.001] [main] [Client.java:26] ([INFO][com.example.testsb.testrmi.client.Client] hello_world
[2024-03-19 07:14:30.003] [main] [Client.java:33] ([INFO][com.example.testsb.testrmi.client.Client] SCLogin(uid=1)
 */

总结:

1.rmi可以看出来非常简单。

2.基于java的序列化和反序列化。

3.已解决粘包问题。

相关推荐
++==2 天前
RPC:grpc的使用与安装、server和client的使用示例、lsb_relese、自定制协议(LVC)+protobuf的RPC调用框架的实现
网络·网络协议·rpc
码匠许师傅4 天前
【设计模式精讲】21.迭代器模式(Iterator)
c++·设计模式·rpc·迭代器模式·软件工程·uml
天天喝旺仔4 天前
gRPC 流式通信实战:从一元调用到双向流,吃透四种 RPC 模式(Go 版)
分布式·http·微服务·rpc·go
可爱系程序猿7 天前
添加网络打印机提示 0x000006ba:从 RPC 服务、Print Spooler 到主机发现排查
网络·网络协议·rpc
可爱系程序猿8 天前
Windows 11 添加共享打印机提示 0x00000bc4:从 RPC 发现到策略配置排查
windows·网络协议·rpc
Patrick_Wilson12 天前
RPC 与 REST 的本质区别看这一篇就够了:别再只看 URL 里有没有动词
http·rpc·restful
catino12 天前
spring-IOC、DI
java·spring·rpc
头茬韭菜12 天前
功能点 11-12:客户端、RPC 通信、监控与安全
网络协议·安全·rpc·fluss
JackSparrow41414 天前
Kafka(七)集成Apache Avro+Apicurio Schema Registry以保障生产者与消费者的消息兼容性
java·中间件·rpc·kafka·apache·avro·schema-registry
爱学堂IT分享14 天前
码神之路-Netty-从零实现RPC框架+SpringBoot实战项目教程
spring boot·网络协议·rpc