个人备案网站能做什么/策划方案模板

个人备案网站能做什么,策划方案模板,电商系统开发解决方案,wampserver搭建网站目录 rpc(Remote Procedure Call)rpc一般架构为什么要引入rpc自己实现rpc调用1. 新建一个maven项目,加入hessian依赖2. 服务端3. Stub代理4. 客户端测试输出5. rpc程序分析附 请求参数和序列化程序 6. 总结 回顾RPCRPC 序列化协议RPC 网络协议注册中心的引入dubbo框…

目录

  • rpc(Remote Procedure Call)
    • rpc一般架构
    • 为什么要引入rpc
    • 自己实现rpc调用
      • 1. 新建一个maven项目,加入hessian依赖
      • 2. 服务端
      • 3. Stub代理
      • 4. 客户端测试输出
      • 5. rpc程序分析
        • 附 请求参数和序列化程序
      • 6. 总结
    • 回顾RPC
      • RPC 序列化协议
      • RPC 网络协议
      • 注册中心的引入
      • dubbo框架看一个rpc框架的实现架构

rpc(Remote Procedure Call)

Remote Procedure Call (RPC) is a powerful technique for constructing distributed, client-server based applications. It is based on extending the conventional local procedure calling so that the called procedure need not exist in the same address space as the calling procedure. The two processes may be on the same system, or they may be on different systems with a network connecting them.

rpc一般架构

在这里插入图片描述

  • 客户端(Client):服务调用方
  • 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息(序列化),再通过网络传输发送给服务端
  • Network Service:底层传输,可以是 TCP 或 HTTP,或其它网络协议
  • 服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包(反序列化),然后再调用本地服务进行处理
  • 服务端(Server):服务的真正提供者

为什么要引入rpc

两台不同的主机进程要进行通信?

最易想到的最原始做法:tcp/ip通信,二进制数据传输

蛮烦点在于:要写网络相关处理;对方服务进行动态扩展后,客户端又得重新对接处理。最好能能像本地调用localService.doSth()一样,能调用B机器的bService.doSth(), C机器的cService.doSth()

要解决这个问题,提升开发效率,由此开始了rpc的引入,下面通过java编程来完成这一基本目标

自己实现rpc调用

基础知识点如下,其实很基础,就是大一学生学完Java就基本能操作

  • JAVA socket编程基础
  • JAVA反射
  • 代理模式/动态代理
  • 序列化

1. 新建一个maven项目,加入hessian依赖

项目结构如下:
在这里插入图片描述

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rpc</groupId><artifactId>rpctest</artifactId><version>1.0-SNAPSHOT</version><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build><dependencies><dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.38</version></dependency></dependencies></project>

2. 服务端

package com;import com.entity.RpcRequest;
import com.service.impl.ProServiceImpl;
import com.service.impl.UserServiceImpl;
import com.util.HessianSerializerUtil;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;/*** @Author mubi* @Date 2020/5/18 23:18*/
public class Server {public static void main(String[] args) throws Exception {// 监听指定的端口final int port = 55533;ServerSocket server = new ServerSocket(port);// server将一直等待连接的到来System.out.println("server将一直等待连接的到来");while (true) {Socket client = server.accept();System.out.println("accept client:" + client.getPort());new Thread(() -> {try {// 建立好连接后,从socket中获取客户端传递过来的对象InputStream in = client.getInputStream();RpcRequest rpcRequest = HessianSerializerUtil.deserialize(readInputStream(in));System.out.println("rpcRequest:" + rpcRequest);// 执行方法,// 需要从服务注册中找到具体的类,这里模拟判断Class clazz = null;if (rpcRequest.getClassName().equals("com.service.IUserService")) {clazz = UserServiceImpl.class;}if (rpcRequest.getClassName().equals("com.service.IProService")) {clazz = ProServiceImpl.class;}Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getParamTypes());Object o = method.invoke(clazz.newInstance(), rpcRequest.getArgs());// 返回对象 二进制形式发送给客户端OutputStream out = client.getOutputStream();out.write(HessianSerializerUtil.serialize(o));out.flush();client.close();} catch (Exception e) {}}).start();}
//        server.close();}public static byte[] readInputStream(InputStream inputStream) throws IOException {byte[] buffer = new byte[2048];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((len = inputStream.read(buffer)) != -1) {bos.write(buffer, 0, len);}return bos.toByteArray();}}

3. Stub代理

package com;import com.entity.RpcRequest;
import com.util.HessianSerializerUtil;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;/*** @Author mubi* @Date 2020/5/18 23:18*/
public class Stub {public static Object getStub(Class clazz){// 调用方法处理器InvocationHandler h = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 要连接的服务端IP地址和端口final String host = "127.0.0.1";final int port = 55533;// 与服务端建立连接Socket socket = new Socket(host, port);// 构造请求服务器的对象RpcRequest rpcRequest = new RpcRequest(clazz.getName(), method.getName(),method.getParameterTypes(), args);// 传递二进制给服务端OutputStream outputStream = socket.getOutputStream();outputStream.write(HessianSerializerUtil.serialize(rpcRequest));socket.shutdownOutput();// 直接读取服务端返回的二进制, 反序列化为对象返回InputStream inputStream = socket.getInputStream();byte[] bytes = readInputStream(inputStream);Object o = HessianSerializerUtil.deserialize(bytes);inputStream.close();outputStream.close();socket.close();return o;}};Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);System.out.println(o.getClass().getInterfaces()[0]);return o;}public static byte[] readInputStream(InputStream inputStream) throws IOException {byte[] buffer = new byte[2048];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((len = inputStream.read(buffer)) != -1) {bos.write(buffer, 0, len);}return bos.toByteArray();}}

4. 客户端测试输出

package com;import com.service.IProService;
import com.service.IUserService;/*** @Author mubi* @Date 2020/5/18 23:18*/
public class Client {public static void main(String[] args) {IUserService iUserService = (IUserService) Stub.getStub(IUserService.class);System.out.println(iUserService.getUserById(12));IProService iProService = (IProService) Stub.getStub(IProService.class);System.out.println(iProService.getProById(12));}}

输出如下:
在这里插入图片描述

可以看到客户端使用远程服务像本地服务一样的调用了

5. rpc程序分析

 public static Object getStub(Class clazz){// 调用方法处理器InvocationHandler h = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 要连接的服务端IP地址和端口final String host = "127.0.0.1";final int port = 55533;// 与服务端建立连接Socket socket = new Socket(host, port);// 构造请求服务器的对象RpcRequest rpcRequest = new RpcRequest(clazz.getName(), method.getName(),method.getParameterTypes(), args);// 传递二进制给服务端OutputStream outputStream = socket.getOutputStream();outputStream.write(HessianSerializerUtil.serialize(rpcRequest));socket.shutdownOutput();// 直接读取服务端返回的二进制, 反序列化为对象返回InputStream inputStream = socket.getInputStream();byte[] bytes = readInputStream(inputStream);Object o = HessianSerializerUtil.deserialize(bytes);inputStream.close();outputStream.close();socket.close();return o;}};Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);System.out.println(o.getClass().getInterfaces()[0]);return o;}

可以看到使用了java动态代理,客户端拿到的ServiceImpl实际上是个代理对象,

调用行为进行了代理,如下几个步骤

  1. 网络请求socket连接服务端
  2. 使用hessian将参数 序列化,转化为字节流,进行socket通信
  3. 服务端socket通信,hessian 反序列化客户端传入的参数,然后反射完成服务的调用,然后 序列化 返回结果
  4. 客户端收到服务端响应,反序列化结果,输出
附 请求参数和序列化程序
  • RpcRequest
package com.entity;import java.io.Serializable;
import java.util.Arrays;/*** rpc请求通用参数结构* @Author mubi* @Date 2020/5/18 23:10*/
public class RpcRequest implements Serializable {String className;String methodName;Class[] paramTypes;Object[] args;public RpcRequest(String className, String methodName, Class[] paramTypes, Object[] args) {this.className = className;this.methodName = methodName;this.paramTypes = paramTypes;this.args = args;}public String getClassName() {return className;}public String getMethodName() {return methodName;}public Class[] getParamTypes() {return paramTypes;}public Object[] getArgs() {return args;}@Overridepublic String toString() {return "RpcRequest{" +"className='" + className + '\'' +", methodName='" + methodName + '\'' +", paramTypes=" + Arrays.toString(paramTypes) +", args=" + Arrays.toString(args) +'}';}
}
  • HessianSerializerUtil
package com.util;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.entity.User;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;public class HessianSerializerUtil {public static <T> byte[] serialize(T obj) {byte[] bytes = null;// 1、创建字节输出流ByteArrayOutputStream bos = new ByteArrayOutputStream();// 2、对字节数组流进行再次封装// step 1. 定义外部序列化工厂//ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();//extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());//extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());// step 2. 序列化工厂//SerializerFactory serializerFactory = new SerializerFactory();//serializerFactory.addFactory(extSerializerFactory);HessianOutput hessianOutput = new HessianOutput(bos);//hessianOutput.setSerializerFactory(serializerFactory);try {// 注意,obj 必须实现Serializable接口hessianOutput.writeObject(obj);bytes = bos.toByteArray();} catch (IOException e) {e.printStackTrace();}return bytes;}public static <T> T deserialize(byte[] data) {if (data == null) {return null;}// 1、将字节数组转换成字节输入流ByteArrayInputStream bis = new ByteArrayInputStream(data);// step 1. 定义外部序列化工厂//ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();//extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());//extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());// step 2. 序列化工厂//SerializerFactory serializerFactory = new SerializerFactory();//serializerFactory.addFactory(extSerializerFactory);HessianInput hessianInput = new HessianInput(bis);//hessianInput.setSerializerFactory(serializerFactory);Object object = null;try {object = hessianInput.readObject();} catch (IOException e) {e.printStackTrace();}return (T) object;}static void test() throws Exception{User user = new User(1, "wang");byte[] bytes = HessianSerializerUtil.serialize(user);System.out.println(user);User user1 = HessianSerializerUtil.deserialize(bytes);System.out.println(user1);}public static void main(String[] args) throws Exception {test();}
}

6. 总结

程序其实完成了如下图:
在这里插入图片描述

通过最基础的java反射、态代理、socket编程等就实现了简单的类似rpc调用

接下来不管多少种服务;只要双方约定好,客户端直接调用即可,基本不需要修改Stub相关代码; client 调用远程方法,就像调用本地方法一样(客户端同学都不需要懂网络底层,直接服务端有什么,就能用什么)

回顾RPC

在这里插入图片描述

RPC 序列化协议

RPC(Remote Procedure Call,远程过程调用)序列化协议是用于在网络上传输数据的一种机制,特别是在客户端和服务器之间传输函数调用请求和响应时。序列化是将数据结构或对象状态转换为可以存储或传输的格式的过程。在RPC通信中,序列化是关键步骤,因为它使得数据能够在网络上安全传输并被另一端正确解析。

常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;

  • JSON是一种轻量级的数据交换格式,易于阅读和编写,支持跨语言使用。然而,JSON的序列化和反序列化速度较慢,且序列化后的数据体积较大,不适合对性能要求较高的场景‌

  • Protobuf‌:由谷歌开发,支持多语言平台,序列化后的数据体积小,序列化速度快。它需要预编译IDL文件,适用于需要高效数据传输和存储的场景‌

  • Thrift‌:由Facebook开发,支持跨语言服务开发,序列化速度快,数据体积小。Thrift既是传输协议也是序列化协议,适用于需要高效数据处理的分布式系统‌

  • Hessian‌:主要用于Web服务的序列化和反序列化,支持跨语言调用,但相对于其他协议,Hessian的性能略逊一筹‌

RPC 网络协议

如下通信协议

  • TCP/UDP
  • Web Service
  • Restful(http + json)
  • RMI(Remote Method Invocation)
  • JMS(Java Message Service)
  • RPC(Remote Procedure Call)

不过本质还是掌握Socket编程,了解网络IO相关知识

注册中心的引入

随着服务数量的增多,各个服务之间的调用变得错综复杂,一个服务可能依赖外部多个服务,当一个服务的域名或IP地址改变了之后如何通知依赖方,或者依赖方如何快速的发现服务提供方的地址变化。

两种方案:

  1. 客户端与服务端自己维护:有多少个服务,客户端就要维护多少个(服务增减,负载均衡,心跳)
  2. 找个代理,客户端有需求找代理,代理维持这些服务,也能给客户通知;(可以看成代理模式

在这里插入图片描述

显然是注册中心的方式更加合理和方便。

服务中心可以进行服务注册,类似维护一个登记簿,它管理系统内所有的服务地址。当新的服务启动后,它会向登记簿交待自己的地址信息。服务的依赖方直接向登记簿要Service Provider地址就行了,或者基于某种约定(负载均衡)拿到服务的一个具体实例进行通信就好了

回顾springboot+dubbo+zookeeper的注册服务和调用实践:https://blog.csdn.net/qq_26437925/article/details/145790590

dubbo框架看一个rpc框架的实现架构

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/70569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32 USB】USB CDC类

简介 USB CDC&#xff08;communication device class&#xff09;类是usb2.0标准下的一个子类&#xff0c;定义了通信相关设备的抽象集合。usb2.0标准下定义了很多子类&#xff0c;有音频类&#xff0c;CDC类&#xff0c;HID类&#xff0c;打印&#xff0c;大容量存储类&…

如何修改Windows系统Ollama模型存储位置

默认情况下&#xff0c;Ollama 模型会存储在 C 盘用户目录下的 .ollama/models 文件夹中&#xff0c;这会占用大量 C 盘空间&#xff0c;增加C盘“爆红”的几率。所以&#xff0c;我们就需要修改Ollama的模型存储位置 Ollama提供了一个环境变量参数可以修改Ollama的默认存在位…

Codes 开源免费研发项目管理平台 2025年第一个大版本3.0.0 版本发布及创新的轻IPD实现

Codes 简介 Codes 是国内首款重新定义 SaaS 模式的开源项目管理平台&#xff0c;支持云端认证、本地部署、全部功能开放&#xff0c;并且对 30 人以下团队免费。它通过创新的方式简化研发协同工作&#xff0c;使敏捷开发更易于实施。并提供低成本的敏捷开发解决方案&#xff0…

uniapp 网络请求封装(uni.request 与 uView-Plus)

一、背景 在开发项目中&#xff0c;需要经常与后端服务器进行交互&#xff1b;为了提高开发效率和代码维护性&#xff0c;以及降低重复性代码&#xff0c;便对网络请求进行封装统一管理。 二、创建环境文件 2.1、根目录新建utils文件夹&#xff0c;utils文件夹内新建env.js文…

ESP32-S3 实战指南:BOOT-KEY 按键驱动开发全解析

一、基础知识 本篇我们使用 BOOT 按键来学习一下 GPIO 功能&#xff0c;首先补充一下相关术语介绍。 1、GPIO&#xff08;General Purpose Input/Output&#xff09; GPIO 是微控制器上的通用引脚&#xff0c;既可以作为输入&#xff08;读取外部信号&#xff09;&#xff0…

初学者如何设置以及使用富文本编辑器[eclipse版]

手把手教你设置富文本编辑器 参考来源&#xff1a;UEditor Docs 初学者按我的步骤来就可以啦 一、设置ueditor编辑器 1.提取文件[文章最底部有链接提取方式] 2.解压文件并放到自己项目中&#xff0c;在WebContent目录下&#xff1a; 3. 修改jar包位置路径 到--> 注意&a…

25轻化工程研究生复试面试问题汇总 轻化工程专业知识问题很全! 轻化工程复试全流程攻略 轻化工程考研复试真题汇总

轻化工程复试心里没谱&#xff1f;学姐带你玩转面试准备&#xff01; 是不是总觉得老师会问些刁钻问题&#xff1f;别焦虑&#xff01;其实轻化工程复试套路就那些&#xff0c;看完这篇攻略直接掌握复试通关密码&#xff01;文中有重点面试题可直接背~ 目录 一、这些行为赶紧避…

企业数据集成:实现高效调拨出库自动化

调拨出库对接调出单-v&#xff1a;旺店通企业奇门数据集成到用友BIP 在企业信息化管理中&#xff0c;数据的高效流转和准确对接是实现业务流程自动化的关键。本文将分享一个实际案例&#xff0c;展示如何通过轻易云数据集成平台&#xff0c;将旺店通企业奇门的数据无缝集成到用…

如何调整CAN位宽容忍度?

CAN位宽容忍度是指在控制器局域网络&#xff08;CAN, Controller Area Network&#xff09;中允许时钟同步的误差范围。这是CAN网络正常通信时的关键因素之一&#xff0c;因为CAN协议依赖位同步来确保多个节点在总线上正确解码数据。CAN位宽容忍度确保节点之间由于时钟偏差或抖…

Django-Vue 学习-VUE

主组件中有多个Vue组件 是指在Vue.js框架中&#xff0c;主组件是一个父组件&#xff0c;它包含了多个子组件&#xff08;Vue组件&#xff09;。这种组件嵌套的方式可以用于构建复杂的前端应用程序&#xff0c;通过拆分功能和视图&#xff0c;使代码更加模块化、可复用和易于维…

MySql数据库运维学习笔记

数据库运维常识 DQL、DML、DCL 和 DDL 是 SQL&#xff08;结构化查询语言&#xff09;中的四个重要类别&#xff0c;它们分别用于不同类型的数据库操作&#xff0c;下面为你简单明了地解释这四类语句&#xff1a; 1. DQL&#xff08;数据查询语言&#xff0c;Data Query Langu…

如何为自己的 PDF 文件添加密码?在线加密 PDF 文件其实更简单

随着信息泄露和数据安全问题的日益突出&#xff0c;保护敏感信息变得尤为重要。加密 PDF 文件是一种有效的手段&#xff0c;可以确保只有授权用户才能访问或修改文档内容。本文将详细介绍如何使用 CleverPDF 在线工具为你的 PDF 文件添加密码保护&#xff0c;确保其安全性。 为…

UEFI Spec 学习笔记---9 - Protocols — EFI Loaded Image

本节定义EFI_LOADED_IMAGE_PROTOCOL和 EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL。这些协议分别描述了已加载到内存中的映像&#xff0c;并指定了PE/COFF映像通过EFI引导服务LoadImage()加载 时使用的设备路径。这些描述包括 load image 的源、映像在内存中的当前位置、为image分…

pycharm中配置PyQt6详细教程

PyQt6 是 Qt 框架的 Python 绑定库,基于 Qt 6 开发,专为创建跨平台图形用户界面(GUI)应用程序设计。 本章教程,主要记录在pycharm中配置使用PyQt6的流程。 一、安装基础环境 在此之前,你需要提前安装好Python解释器,推荐使用anaconda创建虚拟环境。 conda create -n pyt…

Java+SpringBoot+Vue+数据可视化的综合健身管理平台(程序+论文+讲解+安装+调试+售后)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统介绍 在当今社会&#xff0c;随着人们生活水平的不断提高和健康意识的日益增强&#xff0c;健…

【从0做项目】Java音缘心动(2)———登录、统一返回设计

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;登录模块设计 1&#xff1a;实体类 2&#xff1a;登录的请求和响应设计 二&#xff…

【Linux网络】认识协议(TCP/UDP)、Mac/IP地址和端口号、网络字节序、socket套接字

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、初识协议2、UDP、TCP3、Mac、IP地址4、端口号5、网络字节序6、socket 1、初识协议 协议就是一种约定。如何让不同厂商生产的计…

【个人开源】——从零开始在高通手机上部署sd(二)

代码&#xff1a;https://github.com/chenjun2hao/qualcomm.ai 推理耗时统计 单位/ms 硬件qnncpu_clipqnncpu_unetqnncpu_vaehtp_cliphtp_unethtp_vae骁龙8 gen124716.994133440.39723.215411.097696.327 1. 下载依赖 下载opencv_x64.tar,提取码: rrbp下载opencv_aarch64.t…

从混沌到有序:一个数据血缘分析的进化故事

从混沌到有序&#xff1a;一个数据血缘分析的进化故事 从混沌到有序的数据治理之路数据血缘的建设方法和实践路径数据血缘的实践场景和未来趋势。 数据就像流淌在企业血管中的血液&#xff0c;它的每一次流动、每一次转化都留下独特的印记。 作为数据工程师&#xff0c;我曾困惑…

图表控件Aspose.Diagram入门教程:使用 Python 将 VSDX 转换为 PDF

将VSDX转换为PDF可让用户轻松共享图表。PDF 文件保留原始文档的布局和设计。它们广泛用于演示文稿、报告和文档。在这篇博文中&#xff0c;我们将探讨如何在 Python 中将 VSDX 转换为 PDF。 本文涵盖以下主题&#xff1a; Python VSDX 到 PDF 转换器库使用 Python 将 VSDX 转…