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

相关推荐
一休哥助手4 天前
Apache Thrift:跨语言服务开发的高性能RPC框架指南
网络协议·rpc·apache
siriuuus5 天前
Linnux IPC通信和RPC通信实现的方式
rpc·网络通信
波波烤鸭5 天前
Netty 实战应用:从 RPC 到即时通讯,再到 WebSocket
websocket·网络协议·rpc
晴天下小雨o6 天前
Json-rpc通信项目(基于C++ Jsoncpp muduo库)
c++·rpc·json
Sui_Network6 天前
GraphQL RPC 与通用索引器公测介绍:为 Sui 带来更强大的数据层
javascript·人工智能·后端·rpc·去中心化·区块链·graphql
yb0os17 天前
RPC实战和核心原理学习(一)----基础
java·开发语言·网络·数据结构·学习·计算机·rpc
qq_172805597 天前
GO RPC 教学文档
qt·rpc·golang
roshy7 天前
RPC 与http对比
网络协议·http·rpc
却尘8 天前
Server Actions 深度剖析:这就是个披着 React 外衣的 RPC
前端·rpc·next.js
bantinghy9 天前
RPC内核细节(转载)
linux·服务器·网络·网络协议·rpc