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

相关推荐
mit6.8241 天前
[实现Rpc] 通信类抽象层 | function | using | 解耦合设计思想
c++·网络协议·rpc
卷心菜不卷Iris1 天前
第1章大型互联网公司的基础架构——1.6 RPC服务
网络·网络协议·微服务·rpc·http协议·rpc协议
zhj16953691 天前
手写简易RPC(实践版)
java·网络·网络协议·rpc
lzb_kkk1 天前
【C++项目】Rpc通信框架设计
linux·网络·c++·网络协议·ubuntu·rpc
mit6.8242 天前
[实现Rpc] 消息类型的测试 | dynamic_pointer_cast | gdb使用
c++·rpc
mit6.8242 天前
[实现Rpc] 消息抽象层的具体实现
c++·网络协议·rpc
YGGP6 天前
【GeeRPC】Day6:负载均衡
rpc·golang·负载均衡
suuijbd9 天前
浅谈自己对RPC的理解
网络·网络协议·rpc
陈老师还在写代码9 天前
讲解一下SpringBoot的RPC连接
spring boot·后端·rpc
YGGP10 天前
【GeeRPC】Day5:支持 HTTP 协议
http·rpc·golang