RPC远程调用

这篇具有很好参考价值的文章主要介绍了RPC远程调用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

PRC是一种调用方式而不是一种协议
RPC远程调用
在本地调用方式时由于方法在同一个内存空间,所以程序中可以直接调用该方法,但是浏览器端和服务端程序是不在一个内存空间的,需要使用网络来访问,就需要使用TCP或者UDP协议,由于TPC协议是面向连接,基于字节流的,使用起来不太方便,于是在此基础上衍生了http,gprc等协议。

RPC协议底层可以使用http协议或者TCP协议。

为什么需要rpc协议:
RPC远程调用
RPC远程调用

RPC协议是主机之间的调用协议,HTTP是浏览器和主机之间的调用协议。

不同主机之间服务远程调用时由于需要通过网络,所以需要定义很多规则,RPC远程调用方式就是希望远程调用方法时像本地调用方法一样省去过多的细节。基于远程调用方式也衍生一些协议如,gPRC,thrift。

RPC远程调用

HtppClient

RPC远程调用
HttpClinet就是在服务器端通过Java代码模拟一个小型浏览器,获取获取数据后进行序列化与反序列化操作。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

注意是Apache的HttpClinet

RPC远程调用

  • 控制器服务
@RestController
@RequestMapping("/test")
public class TestControoler {
    @GetMapping("/hello")
    String Hello(){
        return "Hello";
    }
}
  • HttpClient远程代用服务
@RestController
@RequestMapping("/http")
public class HttpCilentController {
    
    @GetMapping("/getHello")
    String gethello(){
        //声明响应类
        HttpResponse execute = null;
        //创建http服务端实例
        HttpClient client = HttpClients.createDefault();
        //发送请求
        HttpGet get = new HttpGet("http://localhost:8080/test/hello");
        try {
             execute = client.execute(get);
        }catch (IOException e){ e.printStackTrace();}
        //获取响应体
        HttpEntity entity = execute.getEntity();
        //工具了解析
        String str = null;
        try {
            str = EntityUtils.toString(entity, "utf-8");
        }catch (IOException e){e.printStackTrace();}
        //这里的String就是一个json字符串,如果该字符串是一个类免责需要再次使用工具如jackson,fastjson将josn字符串转为类。

        return str;
    }
    
}

RPC远程调用
RPC远程调用

在B远程调用的A过程中,实际上是在B的服务内部实现了一个浏览器服务请求服务器返回JSON字符。

RestTemplate

RestTemplate是基于spring封装的HttpClient。在任何Java项目导入httpclient依赖后就可以使用。RestTemplate只能在spring项目中使用,并且spring本身封装了HttpClient,使用起来也更方便。

HttpClient是一种用于发送HTTP请求的原生Java库,Apache Commons HttpClient是建立在HttpClient基础上的第三方工具类库,RestTemplate是Spring框架中封装的HTTP请求操作类,Feign是一种声明式的Web服务客户端,Forest是一个为微服务开发而编写的客户端应用程序框架,他们的实现都是基于HttpClient的。

在后续的学习中还会接触到spring cloud的Feign。另外还有其他框架对HttpClient封装是其操作更加方便。如Forest,okhttp等。除了OkHttp只支持HTTP请求外,其他工具都支持Http和https协议。不同的是,HttpClient和Forest是对同一个底层框架的封装,在性能上比Okhttp要好很多;RestTemplate和Feign都是基于Spring框架的封装,支持并发,实现起来更易于维护。

@RestController
@RequestMapping("/template")
public class TemplateControoler {
    RestTemplate restTemplate = new RestTemplate();
    @GetMapping("/getHello")
    String getStr(){
        String str = restTemplate.getForObject("http://localhost:8080/test/hello",String.class);
        return str;
    }
}

在spring中只需要少量的代码就可以完成功能,更加方便简洁。

RPC远程调用

RMI

RMI: 远程方法调用(Remote Method Invocation),它支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。

RPC远程调用

前两种实现RPC的方式是基于HTTP协议的,那么就需要在服务端模拟浏览器请求。RMI是直接基于TCP协议的。

RPC远程调用
Java RMI: 用于不同虚拟机之间的通信,这些虚拟机可以在不同的主机上、也可以在同一个主机上;一个虚拟机中的对象调用另一个虚拟上中的对象的方法,只不过是允许被远程调用的对象要通过一些标志加以标识,底层是通过Socket通信来进行实现的。

RPC远程调用

  • 返回类
class Person{
    private String name;
    private int age;
    private String address;


    Person(String name,int age,String address){
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
  • 控制器
@RestController
@RequestMapping("/rmi")
public class RmiControoler {
    @GetMapping("/hello")
    String Hello(){
        return "Hello";
    }
    
    @GetMapping("/person")
    Person person() throws RemoteException {return new TestServiceImpl().sendPerson();}
}
  • rmi注册中心
public class RegisterCenter {
    public static void main(String[] args) {
        try {
            // 创建本机上的远程对象注册表Registry的实例,默认端口1099
            LocateRegistry.createRegistry(1099);
            // 创建一个对象
            TestServiceImpl testService = new TestServiceImpl();

            // 把远程对象注册到RMI注册服务器上,testService
            //绑定的URL标准格式为:rmi://host:port/name
            //registry.rebind("testService", testService);
            //Naming.rebind("rmi:localhost:1099/testService",testService);
            Naming.rebind("testService",testService);
            System.out.println("======= 启动RMI服务成功! =======");
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}
  • 服务类
//服务接口

public interface TestService extends Remote {
    public String sendHello() throws RemoteException ;
    public Person sendPerson() throws RemoteException ;
}

// 服务实现类
/*
服务的方法实现类必须直接或简洁继承Remote并抛出RemoteException
 */
public class TestServiceImpl extends UnicastRemoteObject implements TestService {

    public TestServiceImpl() throws RemoteException {
        super();
    }

    public String sendHello (){return "Hello";}

    public Person sendPerson(){return new Person("xiaoxu",22,"北京");}


}
  • 客户端远程调用
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RmiClient {
    public static void main(String[] args) {
        try {
            //创建RMI注册中心实例(通过socket连接)
            Registry registry = LocateRegistry.getRegistry(1099);
            //远程调用对象的实例化
            Remote testService = registry.lookup("testService");
            //类型强转
            Person person = (Person) testService;
            System.out.println("=======> " + person + " <=======");
        } catch (NotBoundException | RemoteException e) {
            e.printStackTrace();
        }
    }
}

启动主程序和注册中心

RPC远程调用
正常访问远程服务器返回参数
RPC远程调用

java.rmi.NotBoundException: testService

RPC远程调用

如上图所示,报错了,出现该问题可以是服务为注册到注册中心,或者名称错误,检查了好几遍,像如下的格式来回改,还是没成功:

registry.rebind("testService", testService);       

Naming.rebind("rmi:localhost:1099/testService",testService);

最后发现了问题所在,在注册中心上下文脱节了,并没成功注册:

RPC远程调用

重构项目,注册中心和注册方法分开,如下:

RPC远程调用

将注册中心和注册方法分离,如下:

//注册中心,功能单一生成一个注册中心
public class RegisterCenter {
    public static void main(String[] args) {
        try {
            // 创建本机上的远程对象注册表Registry的实例,默认端口1099
            LocateRegistry.createRegistry(1099);
            System.out.println("======= 启动RMI服务成功! =======");
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
//注册方法,将类注册到注册中心
public class Register {
    public static void main(String[] args) throws RemoteException {
        //获取注册中心
        Registry registry = LocateRegistry.getRegistry(1099);
        // 创建一个对象
        TestServiceImpl testService = new TestServiceImpl();
        // 把远程对象注册到RMI注册服务器上,testService
        //绑定的URL标准格式为:rmi://host:port/name
        registry.rebind("testService", testService);
       
    }
}

注意注册中心注册的是类,但是类一般都有实现方法,而在其他主机上显然是没有该类的,因为实现类的耦合度高,所以必须使用接口,让实现类实现接口,这样,其他主机上只需要实现接口,就能接受实现类了,也是面向对象多态性的体现。

//客户端远程rmi调用
public class RmiClient {
    public static void main(String[] args) {
        try {
            //创建RMI注册中心实例(通过socket连接)
            Registry registry = LocateRegistry.getRegistry(1099);
            //远程调用对象的实例化
            Remote obj = registry.lookup("testService");
            //Remote obj = Naming.lookup("rmi://:1099/testService");
            //类型强转
            TestService testService = (TestService) obj;
            System.out.println(testService.sendHello());
            //System.out.println("=======> " + testService.sendPerson().toString() + " <=======");
        } catch (NotBoundException | RemoteException e) {
            e.printStackTrace();
        }
    }
}

先启动注册中心,在启动注册任务,最后客户端远程调用:
RPC远程调用

上述是通过Registry对象调用的,RMI还提供了该对象的封装类,Naming实现。

注册中心必须和注册任务在一个主机上,这样Java了被注册到注册中心以供RMI注册中心通过协议向外暴露。

注册中心功能单一就是常见注册中心服务器:

LocateRegistry.createRegistry(1099);

注册中心基于自己ip创建,作为服务器,无需指明ip地址。

注册任务程序负责获取创建的注册,并将java类注册到注册中心内:

//获取本机注册中心
Registry registry = LocateRegistry.getRegistry(1099);

//获取指定地址的注册中心
Registry registry1 = LocateRegistry.getRegistry("192.168.223.128",1099);
//注册java类(名称注册默认ip地址)
registry.rebind("testService", testService);

//指定ip地址注册
registry.bind("rmi://192.168.245.1:1099/testService",testService);

Naming实现

Naming.rebind("rmi://192.168.245.1:1099/testService",testService);


Naming.rebind("testService",testService);
Remote obj = Naming.lookup("rmi://192.168.245.1:1099/testService");
Remote obj = Naming.lookup("testService");

参考文章-分布式架构基础:Java RMI详解感谢作者 😃文章来源地址https://www.toymoban.com/news/detail-501353.html

到了这里,关于RPC远程调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于netty的rpc远程调用

    🚀🚀🚀这是一个手写RPC项目,用于实现远程过程调用(RPC)通信🚀🚀🚀 欢迎star串门 : https://github.com/red-velet/ 🚀Q-PRC 简单的RPC框架的实现 :该RPC框架实现了基本的远程过程调用功能,允许客户端通过网络调用远程服务的方法,实现分布式系统之间的通信和协作。 基于

    2024年02月14日
    浏览(35)
  • RPC远程调用加密方法获取返回值

    从混淆的加密JS中还原了加密参数的具体生成流程,结果想从JS转python的过程中第一步就卡住了。开头密钥JS代码如下,但是水平有限不知道如何转为python实现(如果有大佬知道希望可以评论指点)。利用execjs+jsdom来执行简化还原后的JS代码依旧无法实现。所以只能通过RPC的方式来

    2024年02月08日
    浏览(40)
  • RPC:Remote Procedure Call 远程过程调用

    目前,对于一个完整的应用来说,通常包含了若干支持不同功能的服务,亦或者是函数,这些服务之间往往可能需要互相调用,使用已经实现的服务功能,而不是需要在每个服务进程中再去重复实现已经有的功能。 这不仅对于开发者来说是一种比较合理的设计方式,对于服务

    2024年01月19日
    浏览(27)
  • 【C++】开源:grpc远程过程调用(RPC)配置与使用

    😏 ★,° :.☆( ̄▽ ̄)/$: .°★ 😏 这篇文章主要介绍grpc远程过程调用(RPC)配置与使用。 无专精则不能成,无涉猎则不能通。。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 项目Github地址: https://github.com/grpc/grpc 官网

    2024年02月15日
    浏览(48)
  • 【基于netty+zookeeper的rpc远程调用框架】首篇——缘起

    🐼 作者简介:一名大三在校生🎋 空有想法,没有实践 缘起 作为一名即将步入社会的大三学生,我深知一份优秀的简历对于求职的重要性。暑期实习作为大学生涯中的一个重要节点,不仅是锻炼自己、积累经验的宝贵机会,更是向未来雇主展示自己能力和潜力的关键时期。

    2024年04月26日
    浏览(41)
  • Mybatis-Plus+Nacos+Dubbo进行远程RPC调用保姆级教程

    本文通过简单的示例代码和说明,让读者能够了解Mybatis-Plus+Nacos+Dubbo进行远程RPC调用的简单使用  默认你已经看过我之前的教程了,并且拥有上个教程完成的项目, 之前的教程 https://www.cnblogs.com/leafstar/p/17638782.html 项目链接在最后   1.在bank1的pom文件中引入以下依赖   2.使用

    2024年02月12日
    浏览(27)
  • 【SpringBoot集成Nacos+Dubbo】企业级项目集成微服务组件,实现RPC远程调用

    在日益增长的业务需求中,一开始使用的是每个项目独立开发,虽然都是前后端分离的项目,但是每一个项目之间互不干扰。后来,因为某种需求,需要几个项目的数据相互交错获取。 最开始的想法就是集成多个数据源。 举例 有A、B、C三个项目,对应着数据库DBa、DBb、DBc、

    2024年02月04日
    浏览(53)
  • 第四章 RPC 调用

    通过以上案例我们发现,Http请求调用服务实例属实过于麻烦。其实对于请求同一个服务,很多步骤都是相同的,例如:服务名,地址,httpClient 创建步骤等。 RPC的出现,就是为了解决这一问题。 RPC: 即我们常说的远程过程调用,就是像调用本地方法一样调用远程方法,通信协

    2024年02月04日
    浏览(49)
  • 【Go】四、rpc跨语言编程基础与rpc的调用基础原理

    早期 Go 语言不使用 go module 进行包管理,而是使用 go path 进行包管理,这种管理方式十分老旧,两者最显著的区别就是:Go Path 创建之后没有 go.mod 文件被创建出来,而 go module 模式会创建出一个 go.mod 文件用于管理包信息 现在就是:尽量使用 Go Modules 模式 另外,我们在引入包

    2024年02月19日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包