当前位置: 首页 > news >正文

使用Java Socket实现简单版本的Rpc服务

通过如下demo,希望大家可以快速理解RPC的简单案例。如果对socket不熟悉的话可以先看下我的上篇文章 Java Scoket实现简单的时间服务器-CSDN博客 对socket现有基础了解。

RPC简介

RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议,它允许一个程序(客户端)通过网络向另一个程序(服务器)请求服务,而无需了解底层网络技术的细节。RPC 使得开发分布式应用程序更加容易,因为它隐藏了网络通信的复杂性,让开发者能够像调用本地函数一样调用远程函数。

RPC 的主要特点:

  1. 透明性:调用远程过程就像调用本地过程一样,无需关心远程调用的细节。
  2. 跨平台:可以在不同的操作系统和编程语言之间进行通信。
  3. 网络中立:RPC 协议可以运行在各种网络协议之上,如 TCP/IP、HTTP 等。
  4. 语言中立:支持多种编程语言,如 C、C++、Java、Python 等。

RPC 的工作流程:

  1. 客户端调用:客户端调用本地的 RPC 库,传递需要远程执行的函数名和参数。
  2. 序列化:RPC 库将参数序列化成网络传输的格式(如 JSON、XML 或二进制格式)。
  3. 发送请求:客户端通过网络发送序列化后的请求到服务器。
  4. 服务器接收:服务器接收到请求后,反序列化参数。
  5. 执行函数:服务器调用相应的函数执行操作。
  6. 返回结果:服务器将执行结果序列化后发送回客户端。
  7. 客户端接收:客户端接收到结果,反序列化并处理。

RPC 的应用场景:

  • 分布式系统:在分布式系统中,不同的服务可能部署在不同的服务器上,RPC 可以方便地进行服务间的通信。
  • 微服务架构:在微服务架构中,各个微服务之间通常通过 RPC 进行通信。
  • 云服务:云服务提供商可能使用 RPC 来允许用户远程调用云服务。

常见的 RPC 框架:

  • gRPC:由 Google 开发的高性能、开源和通用的 RPC 框架,支持多种语言。
  • Apache Thrift:由 Facebook 开发,后来捐赠给 Apache 基金会,支持多种编程语言。
  • Dubbo:阿里巴巴开源的一个高性能的 Java RPC 框架。
  • XML-RPC 和 JSON-RPC:基于 XML 和 JSON 数据格式的简单 RPC 协议。

RPC 是构建现代分布式系统和微服务架构的关键技术之一。如下是个人对RPC服务的理解示图。

代码实现

1.创建Service以及实现类,由于演示使用的是jdk的动态代理,所以必须得通过接口方式声明资源。代码如下:

HelloService.java

public interface HelloService {String sayHello();}

HelloServiceImpl.java 远程访问的接口实现

public class HelloServiceImpl implements HelloService {@Overridepublic String sayHello() {return "hello world !!!";}
}

参数传输DTO定义,为了简化get、set,请引入lombok工具包:

import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;import java.io.Serializable;@Data
@Accessors(chain = true)
@ToString
public class RequestDTO implements Serializable {/*** 请求函数名称*/private String methodName;/*** 请求参数类型*/private Class<?>[] argsType;/*** 请求的接口*/private String clazz;/*** 请求参数*/private Object[] params;/*** 响应结果*/private Object response;}

服务提供者设计:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Provide {/*** 多线程处理请求*/private static final ExecutorService POOL = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());private static final Map<String,Object> CACHE_MAP = new HashMap<>();public static void main(String[] args) throws Exception {//注册对象registerObject();//启动服务startServer();}/*** 启动服务端*/private static void startServer() throws Exception {ServerSocket serverSocket = new ServerSocket();serverSocket.bind(new InetSocketAddress(9999));System.out.println("服务器启动成功!!!");while (true){Socket socket = serverSocket.accept();POOL.execute(()->{try {ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());RequestDTO request = (RequestDTO)ois.readObject();System.out.println("获取到客户端的请求数据是:"+request);//目标对象Object target = CACHE_MAP.get(request.getClazz());if(null!=target){//反射执行并返回响应结果Method method = target.getClass().getMethod(request.getMethodName(),request.getArgsType());method.setAccessible(true);request.setResponse(method.invoke(target,request.getParams()));}ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(request);socket.getOutputStream().write(bos.toByteArray());socket.getOutputStream().flush();} catch (Exception e) {throw new RuntimeException(e);}finally {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}});}}/*** 注册对象,因为演示,简化自动化扫描注册过程*/private static void registerObject() {CACHE_MAP.put(HelloService.class.getSimpleName(),new HelloServiceImpl());}}

服务调用方实现:

1.动态代理

import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class DynamicProxy<T> {private final String host = "127.0.0.1";private final int port = 9999;/*** 被代理的对象*/private Class<T> clazz;public DynamicProxy(Class<T> clazz){this.clazz = clazz;}/*** 获取代理对象*** @return T*/public T getService(){return (T) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {RequestDTO requestDTO = new RequestDTO().setMethodName(method.getName()).setParams(args).setClazz(clazz.getSimpleName()).setArgsType(method.getParameterTypes());try (Socket socket = new Socket()){//连接客户端socket.connect(new InetSocketAddress(host,port));//进行参数传输ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(requestDTO);oos.flush();socket.getOutputStream().write(baos.toByteArray());socket.getOutputStream().flush();ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());Object o = ois.readObject();if(null==o){return null;}return ((RequestDTO)o).getResponse();} catch (Exception e) {throw new RuntimeException(e);}}});}}

调用过程:


public class Consumer {public static void main(String[] args) {DynamicProxy<HelloService> helloServiceDynamicProxy = new DynamicProxy<>(HelloService.class);HelloService service = helloServiceDynamicProxy.getService();System.out.println(service.sayHello());}}

总结

RPC(远程过程调用)是一种允许一个程序(客户端)通过网络向另一个程序(服务器)请求服务的协议。在RPC框架中,客户端可以像调用本地方法一样调用服务器端的方法,而无需关心底层的网络通信细节。

以下是一段基于Java Socket实现的RPC原理的demo总结:

  1. 服务器端(Server)

    • 创建一个服务器端Socket,监听一个端口等待客户端的连接。
    • 接受客户端的连接请求,创建一个新的线程或者使用线程池来处理客户端请求。
    • 接收客户端发送的请求信息,这通常包括方法名、参数类型和参数值等。
    • 根据请求信息,动态调用对应的本地方法,并获取执行结果。
    • 将方法执行结果返回给客户端。
  2. 客户端(Client)

    • 创建一个客户端Socket,连接到服务器端的IP地址和端口。
    • 封装需要远程调用的方法信息,包括方法名、参数等,并将这些信息发送给服务器。
    • 等待服务器处理请求并返回结果。
    • 接收并解析服务器返回的结果,这可能涉及到对象的反序列化。
  3. 序列化与反序列化

    • 为了通过网络传输方法的参数和返回值,需要将对象序列化成字节流。
    • Java提供了Serializable接口来支持对象的序列化。
    • 客户端发送序列化后的对象,服务器端接收后需要反序列化以恢复对象。
  4. 通信协议

    • 定义了客户端和服务器之间的通信协议,包括请求格式和响应格式。
    • 协议需要规定如何表示方法名、参数列表、返回值等信息。
  5. 异常处理

    • 在网络通信中,可能会遇到各种异常情况,如连接失败、数据传输错误等。
    • 需要在客户端和服务器端都实现异常处理机制,确保系统的健壮性。
  6. 多线程处理

    • 服务器端通常需要处理多个客户端的并发请求。
    • 使用线程池可以有效地管理线程资源,提高系统性能。
  7. 安全性

    • 在实际应用中,需要考虑数据的安全性,比如使用SSL/TLS加密Socket通信。

通过这个Demo,我们可以了解到RPC的核心原理和实现方式,虽然这是一个简化的示例,但它展示了RPC框架的基本工作流程。在实际应用中,RPC框架会提供更复杂的功能,如服务注册与发现、负载均衡、超时重试等。

相关文章:

使用Java Socket实现简单版本的Rpc服务

通过如下demo&#xff0c;希望大家可以快速理解RPC的简单案例。如果对socket不熟悉的话可以先看下我的上篇文章 Java Scoket实现简单的时间服务器-CSDN博客 对socket现有基础了解。 RPC简介 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种…...

P2P 网络 简单研究 1

起因&#xff0c; 目的: P2P 网络&#xff0c; 一道题。题目描述&#xff0c; 在下面。 P2P 网络&#xff0c;我以前只是听说过&#xff0c;并不深入。如果我有5台电脑的话&#xff0c;我也想深入研究一下。 P2P 简介: P2P&#xff08;Peer-to-Peer&#xff09;网络是一种分…...

RAG(检索增强生成)面经(1)

1、RAG有哪几个步骤&#xff1f; 1.1、文本分块 第一个步骤是文本分块&#xff08;chunking&#xff09;&#xff0c;这是一个重要的步骤&#xff0c;尤其在构建与处理文档的大型文本的时候。分块作为一种预处理技术&#xff0c;将长文档拆分成较小的文本块&#xff0c;这些文…...

卫爱守护|守护青春,送出温暖

2024年10月10日&#xff0c;艾多美爱心志愿者来到校园。艾多美“卫艾守护”项目于吉林省白山市政务大厅会议室举办了捐赠仪式&#xff0c;东北区外事部经理黄山出席了捐赠仪式仪式&#xff0c;为全校女同学捐赠了青春关爱包。 此次捐赠&#xff0c;面向吉林省自山市第十八中学、…...

ubuntu-24.04.1 系统安装

使用VMware虚拟机上进行实现 官网下载地址&#xff1a; https://cn.ubuntu.com/download https://releases.ubuntu.com 操作系统手册&#xff1a; https://ubuntu.com/server/docs/ &#xff08;里面包含安装文档&#xff09; 安装指南&#xff08;详细&#xff09;&#xff1a…...

华为OD机试真题---生成哈夫曼树

华为OD机试中关于生成哈夫曼树的题目通常要求根据给定的叶子节点权值数组&#xff0c;构建一棵哈夫曼树&#xff0c;并按照某种遍历方式&#xff08;如中序遍历&#xff09;输出树中节点的权值序列。以下是对这道题目的详细解析和解答思路&#xff1a; 一、题目要求 给定一个…...

小红书新ID保持项目StoryMaker,面部特征、服装、发型和身体特征都能保持一致!(已开源)

继之前和大家介绍的小红书在ID保持以及风格转换方面相关的优秀工作&#xff0c;感兴趣的小伙伴可以点击以下链接阅读~ 近期&#xff0c;小红书又新开源了一款文生图身份保持项目&#xff1a;StoryMaker&#xff0c;是一种个性化解决方案&#xff0c;它不仅保留了面部的一致性&…...

Docker 环境下 GPU 监控实战:使用 Prometheus 实现 DCGM Exporter 部署与 GPU 性能监控

Docker 环境下 GPU 监控实战&#xff1a;使用 Prometheus 实现 DCGM Exporter 部署与 GPU 性能监控 文章目录 Docker 环境下 GPU 监控实战&#xff1a;使用 Prometheus 实现 DCGM Exporter 部署与 GPU 性能监控一 查看当前 GPU 信息二 dcgm-exporter 部署1&#xff09;Docker r…...

联想小新打印机M7328w如何解决卡纸,卡了一个小角在里面,然后再次打印的时候,直接卡住,不能动了。灯显示红色。

1、今天打印一张纸&#xff0c;应该是不小心放歪了&#xff0c;打出来的也是有些斜&#xff0c;然后打出来缺少了个角。 图中的小纸就是从打印机的左边的角&#xff0c;用镊子取出来的&#xff0c;手不太好拿&#xff0c;所以拿个工具比较合适。 2、那么碰到这种卡纸应该如何处…...

软件可靠性之MTTR、MTBF、MTTF、MTTD区别

一.概念解释 1.MTBF&#xff08;Mean Time Between Failures&#xff09;&#xff1a;指两次故障之间的平均时间&#xff0c;通常用于衡量设备或系统的可靠性。 2.MTTF&#xff08;Mean Time to Failure&#xff09;&#xff1a;指设备或系统的平均无故障运行时间。 3.MTTR&am…...

Qt-QDockWidget浮动窗口相关操作(49)

目录 描述 使用 描述 在 Qt 中&#xff0c;浮动窗⼝也称之为铆接部件。浮动窗⼝是通过 QDockWidget类 来实现浮动的功能。浮动窗口⼀般是位于核心部件的周围&#xff0c;可以有多个。 使用 创建我们可以参考下面的语法格式 使用起来也很简单&#xff0c;不过只能创建一个 Q…...

图形用户界面-GUI的基本概念和组件之一

前言 GUI&#xff08;Graphical User Interface&#xff0c;图形用户界面&#xff0c;简称图形界面&#xff09;编程实际是引用java.awt或javax.swing类包中的窗口类、控制组件类、布局类、事件类等&#xff0c;通过将控制组件类&#xff0c;如菜单、按钮、文本框等&#xff0c…...

【MATLAB代码】基于RSSI原理的蓝牙定位程序(N个锚点、三维空间),源代码可直接复制

文章目录 介绍主要功能技术细节适用场景程序结构运行截图源代码详细教程:基于RSSI的蓝牙定位程序1. 准备工作2. 代码结构2.1 清理工作环境2.2 定义参数2.3 生成锚点坐标2.4 定义信号强度与距离的关系2.5 模拟未知点的位置2.6 定位函数2.7 绘图2.8 输出结果2.9 定义定位函数3. …...

Pyenv 介绍和安装指南 - Ubuntu 24

原文&#xff1a; https://www.qiulin-dev.top/articles/81aab753-0d0e-470c-b08f-2643c876841b 1. Pyenv 介绍 Pyenv 是一个非常流行的 Python 版本管理工具&#xff0c;它可以让你在同一台机器上安装并管理多个不同的 Python 版本&#xff0c;解决了不同项目需要不同 Python…...

zookeeper实现RMI服务,高可用,HA

这可不是目录 1.RMI原理与说明1.1含义1.2流程1.3rmi的简单实现1.4RMI的局限性 2.zookeeper实现RMI服务&#xff08;高可用、HA&#xff09;2.1实现原理2.2高可用分析2.3zookeeper实现2.3.1代码分析2.3.2公共部分2.3.3服务端2.3.4客户端2.3.5运行与部署2.3.6效果展示与说明 1.RM…...

通过Express + Vue3从零构建一个用户认证与授权系统(一)项目结构设计

项目背景 本文基于 TypeScript Express Vue3 &#xff0c;从零构建一个用户认证与授权管理系统。这个系统的核心部分包括前端、后端和数据库。我们需要确保各部分合理分层、易于维护和扩展&#xff0c;让我们一步步去实现我们的系统。 一、项目结构设计 1. 前端 (Vue 3 E…...

JavaScript 第13章:Ajax 与异步请求

在Web开发中&#xff0c;异步请求是一种非常重要的技术&#xff0c;它可以让网页在不重新加载的情况下与服务器交互。本章将介绍两种常用的异步请求技术&#xff1a;XMLHttpRequest 和 Fetch API&#xff0c;以及它们如何用于处理JSON数据交换&#xff0c;并通过一个实战案例—…...

速卖通商品详情接口技术解析及Python代码示例

速卖通商品详情接口技术解析及Python代码示例 速卖通&#xff08;AliExpress&#xff09;作为全球知名的跨境电商平台&#xff0c;其开放平台提供了丰富的API接口&#xff0c;允许开发者集成速卖通的各项功能&#xff0c;实现商品搜索、详情查询、订单管理等一系列操作。本文将…...

邻接表的有向网(C语言代码)

#include <stdio.h> #include <stdlib.h> #define MVNum 100 //最大顶点数 //边表结构体 typedef struct ArcNode { //表结点 int adjvex; //邻接点的位置 struct ArcNode* nextarc; //指向下一个…...

大模型生成PPT大纲优化方案:基于 nVidia NIM 平台的递归结构化生成

大模型生成PPT大纲优化方案&#xff1a;基于 nVidia NIM 平台的递归结构化生成 待解决的问题 生成PPT大纲是一种大模型在办公场景下应用的常见需求。 然而&#xff1a; 目前直接让大模型生成大纲往往是非结构化的&#xff0c;输出格式多样&#xff0c;难以统一和规范&#…...

MRSO算法(JCR2区)

原论文摘要&#xff1a;智能技术的快速发展促使利用自然行为来解决复杂问题的优化算法得以发展。其中&#xff0c;鼠群优化算法&#xff08;Rat Swarm Optimizer&#xff0c;RSO&#xff09;受老鼠的社会和行为特征启发&#xff0c;在各个领域已展现出潜力&#xff0c;但其收敛…...

最新Spring Boot3框架入门教程,基础知识讲解(参考官方文档),同时基于MybatisPlus+MYSQL搭建后台管理系统基础流程(附源码)

本文所涉及的代码以及相关文件均上传至仓库:GitHub - yang66-hash/XDPropertyManagementSystemDemo: This is a demo template based on SpringBoot3 in the background of property management system. Spring Boot 是由 Pivotal 团队开发的一款开源框架&#xff0c;它可以帮助…...

导数的概念及在模型算法中的应用

一. 导数概念与计算 1. 导数的物理意义&#xff1a; 瞬时速率。一般的&#xff0c;函数yf(x)在x处的瞬时变化率是 2. 导数的几何意义&#xff1a; 曲线的切线&#xff0c;当点趋近于P时&#xff0c;直线 PT 与曲线相切。容易知道&#xff0c;割线的斜率是当点趋近于 P 时&…...

获取首日涨停封盘后第二次交易日上涨/下跌的概率

有许多投资者喜欢在股票涨停封盘后&#xff0c;跟进买入。普通股民会认为一个能在今日涨停封盘的股票&#xff0c;证明其上市公司正有十分重大的利好信息&#xff0c;只需要跟进购买便可以获取短期利益。 我们用数据来看一下在当日涨停封盘后&#xff0c;第二次交易日是上涨还…...

shell $ 用法

Shell脚本中$符号的几种用法小结_linux shell_脚本之家 Shell 传递参数 | 菜鸟教程 $ 符号说明$0Shell 的命令本身1到9表示 Shell 的第几个参数$?显示最后命令的执行情况$#传递到脚本的参数个数$$脚本运行的当前进程 ID 号$*以一个单字符串显示所有向脚本传递的参数$!后台运行…...

如何用支付宝实现靠脸吃饭

还记得上学时&#xff0c;每当下课铃声响起&#xff0c;我们就会像一群脱缰的野马一样&#xff0c;浩浩荡荡地冲向食堂。最令人崩溃的时刻莫过于终于到达打饭窗口前排时&#xff0c;却发现饭卡忘带了&#xff01;但现在&#xff0c;这种情况将不再发生。许多学校食堂已经配备了…...

Visual Studio的实用调试技巧总结

对于很多学习编程的老铁们来说&#xff0c;是不是也像下面这张图一样写代码呢&#xff1f; 那当我们这样编写代码的时候遇到了问题&#xff1f;大家又是怎么排查问题的呢&#xff1f;是不是也像下面这张图一样&#xff0c;毫无目的的一遍遍尝试呢&#xff1f; 这篇文章我就以 V…...

graphrag学习总结

学习视频&#xff1a;b站链接 项目链接 GraphRAG 的基本概念 Document&#xff08;文档&#xff09;&#xff1a;系统中的输入文档。这些文档要么代表CSV中的单独行&#xff0c;要么代表单独的txt文件。 TextUnit&#xff08;文本块&#xff09;&#xff1a;要分析的文本块。…...

专题:贪心算法(已完结)

1.分发饼干 方法一&#xff1a;用最大的胃口 找到最大的饼干&#xff08;先遍历胃口&#xff09; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 主要思路 用最大的饼干找最大的胃口sort(g.begin(),g.end());so…...

Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式

单机模式 单机模式是Hadoop最简单的运行模式。在单机模式下&#xff0c;所有Hadoop组件都运行在单个机器上&#xff0c;包括HDFS、MapReduce等。由于只有一个节点参与计算&#xff0c;单机模式适用于开发和测试阶段&#xff0c;不适合用于处理大规模数据。在单机模式下&#xf…...