通过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.已解决粘包问题。

相关推荐
jmxwzy2 天前
Spring全家桶
java·spring·rpc
Irene19912 天前
HTTP 请求方法选择与 RESTful 实践(对比 GraphQL、RPC)
rpc·restful·http请求·grpc·graphql
掘根2 天前
【jsonRpc项目】基于注册发现的RPC客户端/服务端
网络·网络协议·rpc
Elias不吃糖3 天前
Spring Bean 注入与容器管理:从“怎么交给容器”到“怎么被注入使用”的完整总结
java·spring·rpc·bean
LuminescenceJ4 天前
GoEdge 开源CDN 架构设计与工作原理分析
分布式·后端·网络协议·网络安全·rpc·开源·信息与通信
七夜zippoe4 天前
gRPC高性能RPC框架实战:从Protocol Buffers到流式传输的完整指南
网络·python·网络协议·rpc·protocol
LuminescenceJ5 天前
RPC通信中的Context上下文如何跨进程传递消息,gRPC为例分析
开发语言·网络·后端·网络协议·rpc·golang
彬匠科技BinJiang_tech5 天前
定制化跨境电商ERP哪家排名性价比高
rpc
datalover5 天前
netty实现rpc
qt·网络协议·rpc