`

RPC

    博客分类:
  • RPC
阅读更多
一、
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议

二、

1.序列化与反序列化

序列化:将对象从内存中以二进制数据流的形式传递
反序列化:将二进制数据传递到内存中

持久化:内存中的数据是不能永久保存的,即瞬时数据,保存到文本中或其他介质中,永久化
反持久化:从持久化转化为内存存储

持久化的前提是序列化,但序列化的目的不一定是为了持久化

2.基本实现

public class Person implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -1170943594852852868L;
	private String name ;
	private Integer age ;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Person(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
	}
	
}


	/**
	 * 序列化:将对象以二进制的格式输出到文本文件中
	 * @throws IOException
	 */
	@Test
	public void testSerializable() throws IOException{
		/**
		 * 所有需要序列化的类均需要实现 Serializable 接口
		 * 标记接口,标识  此类允许序列化与反序列化
		 * java.io.NotSerializableException
		 */
		Person person = new Person();
		person.setName("zhang");
		person.setAge(Integer.valueOf(26));
		// 序列化输出:文件内容为二进制格式,无法直接阅读
		FileOutputStream out = new FileOutputStream("D:\\study\\test.txt");
		ObjectOutputStream oos = new ObjectOutputStream(out);
		
		oos.writeObject(person);
		oos.flush();
		oos.close();
		
	}

	/**
	 * 反序列化:读取文本中的二进制信息
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	@Test
	public void testReverseSerializable() throws IOException, ClassNotFoundException{
		
		FileInputStream in = new FileInputStream("D:\\study\\test.txt");
		ObjectInputStream ois = new ObjectInputStream(in);
		Person person = (Person) ois.readObject();
		System.out.println(person.getName()+" "+person.getAge());
	}


若:
(若实现Serializable ,生成的
private static final long serialVersionUID = 1L;

执行序列化后,修改了Object的属性,增加或删除,再次执行反序列化的时候,异常
解释:
序列化写入的类与反序列化读出的类是两个不同的类,
是因为作用域的原因,写入时,程序执行完毕,内存自动回收
可以认为  读入的类是写入的类的克隆,具有相同的内容

若属性的数量或内容对应不上,克隆就会出现异常

对象序列化即实现Serializable 后,会生成一个随机的serialVersionUID
若属性变化,则会生成新的 serialVersionUID,
进行序列化读出与写入的时候就会比较serialVersionUID是否是同一个
即 serialVersionUID 是序列化与反序列化时的唯一标识

其他:
RPC传输Object时,设置不同机器上的Person的serialVersionUID相同,
即使Person中的内容完全相同,也不一定认为是同一个,即修改serialVersionUID,保持一致

3.transient 不需序列化

public class Person implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -1170943594852852868L;
	private String name ;
	/**
	 * 若某个属性保密,不希望进行系列化处理,加关键字,transient 
	 */
	private transient Integer age ;
	private String gender ;
	
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Person(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
	}
	public Person(String name, Integer age, String gender) {
		super();
		this.name = name;
		this.age = age;
		this.gender = gender;
	}
}



	/**
	 * 序列化:将对象以二进制的格式输出到文本文件中
	 * @throws IOException
	 */
	@Test
	public void testSerializable() throws IOException{
		/**
		 * 所有需要序列化的类均需要实现 Serializable 接口
		 * 标记接口,标识  此类允许序列化与反序列化
		 * java.io.NotSerializableException
		 */
		Person person = new Person();
		person.setName("zhang");
		person.setAge(Integer.valueOf(26));
		person.setGender("male");
		// 序列化输出:文件内容为二进制格式,无法直接阅读
		FileOutputStream out = new FileOutputStream("D:\\study\\test.txt");
		ObjectOutputStream oos = new ObjectOutputStream(out);
		
		oos.writeObject(person);
		oos.flush();
		oos.close();
		
	}

	/**
	 * 反序列化:读取文本中的二进制信息
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	@Test
	public void testReverseSerializable() throws IOException, ClassNotFoundException{
		
		FileInputStream in = new FileInputStream("D:\\study\\test.txt");
		ObjectInputStream ois = new ObjectInputStream(in);
		Person person = (Person) ois.readObject();
		System.out.println(person.getName()+" "+person.getAge()+" "+person.getGender());
	}


输出:
zhang null male

age 属性不需序列化,所以无输出

4.
缺点:
1)只支持java语言,无法跨语言
2)序列化后的数据量比较大
3)执行序列化与反序列化的效率比较低

public class PersonObjectSeriable implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -7328657292302834890L;
	private String name ;
	private transient Integer age ;
	private String gender ;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public PersonObjectSeriable() {
		super();
	}
}




import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.junit.Test;

public class SunSerializableTest {

	@Test
	public void testSerializable() throws IOException{
		PersonObjectSeriable person = new PersonObjectSeriable();
		person.setName("zhang");
		person.setAge(26);
		person.setGender("male");
		
		FileOutputStream out = new FileOutputStream("D:\\study\\java\\PersonObjectSerializable.txt");
		ObjectOutputStream stream = new ObjectOutputStream(out);
		
		stream.writeObject(person);
		stream.flush();
		stream.close();
	}
	
	@Test
	public void testReverseSeriable() throws IOException, ClassNotFoundException{
		
		FileInputStream in = new FileInputStream("D:\\study\\java\\PersonObjectSerializable.txt");
		ObjectInputStream stream = new ObjectInputStream(in);
		
		PersonObjectSeriable person = (PersonObjectSeriable) stream.readObject();
		System.out.println(person.getName()+" "+person.getAge()+" "+person.getGender());
	}
}


三、第三方序列化与反序列化框架

Avro
GoogleProtoBuffer
Thrift


1.GoogleProtoBuffer

生成与执行步骤
1)数据写入   .proto文件
2)编译成类文件
3)导入类文件进行序列化与反序列化

1)PersonProto.proto
package cn.study;// 文件的包路径,便于其他文件引用使用

option java_package = "com.study.rpc.ser.day.one.test"; // 生成的JAVA的类的包名
option java_outer_classname = "PersonProtos"; // JAVA文件名称

message Person{ // 声明类
// required 表示必须,optional 表示可选
// int32 对应 int 类型
// 1,2,3 ... 类中属性的唯一标识,按顺序添加,一旦添加不可更改;否则无法实现序列化
	required string name = 1;
	optional int32 age = 2;
	required string gender = 3;
}



2.编译类文件

解压:protoc.exe 安装包,见 下方

打开 win+r cmd --> cd .. 到安装包目录 --> 将上面的 PersonProto.proto 拷贝到该目录下
执行 protoc.ext --java_out . ./PersonProto.proto




在解压的目录中会出现相应的生成文件




拷贝文件至对应的包中
报错--因为未导入相应的JAR包 -- 见下面链接

3.调用API执行
	@Test
	public void testSerializable() throws IOException{
		
		Person person = Person.newBuilder()
				.setName("zhang").setAge(26).setGender("male").build();
		FileOutputStream output = new FileOutputStream("D:\\study\\java\\PersonObjectProto.txt");
		person.writeTo(output);
				
	}


序列化后的文件大小对比







	@Test
	public void testReverseSerializable() throws IOException{
		
		FileInputStream input = new FileInputStream("D:\\study\\java\\PersonObjectProto.txt");
		Person person = Person.parseFrom(input);
		input.close();
		
		System.out.println(person.getName()+" "+person.getAge()+" "+person.getGender());
		
		
	}


4.扩展
若IO流改为网络流,
接收方以同样的方式对 PersonProto.proto 进行处理,语言可以不同,即不同语言间传递对象

三、RPC实现

描述:客户端发送数据,服务端接收,计算,返回结果给客户端

1.MathService.proto

package cn.study;

option java_package = "com.study.rpc.ser.day.one";
option java_outer_classname = "MathServiceProto";
option java_generic_services = true ; // 是否包含服务

message Req{    // 定义第一个类,接收两个参数
	required int32 num1 = 1;
	required int32 num2 = 2;
}

message Resp{  // 定义第二个类,返回值
	required int32 result = 1;
}

service MathService{  // 定义接口,方法名称 add 参数 Req 返回值 Resp
	rpc add(Req) returns (Resp);
}




生成对应的JAVA文件

2.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

import com.google.protobuf.BlockingRpcChannel;
import com.google.protobuf.Descriptors.MethodDescriptor;
import com.google.protobuf.Message;
import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException;
import com.study.rpc.ser.day.one.MathServiceProto.MathService;
import com.study.rpc.ser.day.one.MathServiceProto.MathService.BlockingInterface;
import com.study.rpc.ser.day.one.MathServiceProto.Req;
import com.study.rpc.ser.day.one.MathServiceProto.Resp;

public class MathClient {

	/**
	 * @param args
	 * @throws ServiceException 
	 */
	public static void main(String[] args) throws ServiceException {

		//stu -- 存根  -- 远程服务在本地的一个代表 
		//-- 具有和远程服务相同的远程调用方法
		//-- 如果本地需要调用远程方法 找到存根调用对应方法即可 
		//-- 存根的底层会自动调用远程的方法来执行并获取结果并返回
		//即:去取钱,但附近没有银行,但有ATM
		//ATM就相当于银行的一个远程服务在本地的代表;取钱 扣款 与去银行是一样的
		BlockingInterface stu = MathService.newBlockingStub(new MyBlockingRPCchannel());
		Req req = Req.newBuilder().setNum1(25).setNum2(26).build();
		Resp resp = stu.add(null, req);
		System.out.println(resp.getResult());
	}

}

class MyBlockingRPCchannel implements BlockingRpcChannel{

	public Message callBlockingMethod(MethodDescriptor methodDescriptor,
			RpcController controller, Message req, Message resp)
			throws ServiceException {
		
		Socket socket = new Socket();
		// 请求连接远程服务器
		try {
			socket.connect(new InetSocketAddress("127.0.0.1", 9999));
			// 发送请求给服务器
			OutputStream out = socket.getOutputStream();
			req.writeTo(out);
			socket.shutdownOutput();
			// 接收服务器返回结果
			InputStream in = socket.getInputStream();
			resp = Resp.parseFrom(in);
			socket.shutdownInput();
			
			return resp;
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null ;
	}
	
}



import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException;
import com.study.rpc.ser.day.one.MathServiceProto.MathService.BlockingInterface;
import com.study.rpc.ser.day.one.MathServiceProto.Req;
import com.study.rpc.ser.day.one.MathServiceProto.Resp;

public class MathService {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {

		ServerSocket server = null ;
		Socket socket = null ;
		
		try {
			server = new ServerSocket();
			server.bind(new InetSocketAddress(9999));
			socket = server.accept();
			
			InputStream input = socket.getInputStream();
			Req req = Req.parseFrom(input);
			socket.shutdownInput();
			
			MyMathService mathService = new MyMathService();
			Resp resp = mathService.add(null, req);
			
			OutputStream out = socket.getOutputStream();
			resp.writeTo(out);
			socket.shutdownOutput();
			
		} catch (ServiceException e) {
			e.printStackTrace();
		}finally{
			socket.close();
			server.close();
		}
		
	}

}

class MyMathService implements BlockingInterface{

	public Resp add(RpcController controller, Req request)
			throws ServiceException {
		int num1 = request.getNum1();
		int num2 = request.getNum2();
		int result = num1 + num2 ;
		Resp resp = Resp.newBuilder().setResult(result).build();
		return resp;
	}
	
}

  • 大小: 2.9 KB
  • 大小: 46 KB
  • 大小: 25.2 KB
  • 大小: 32.8 KB
分享到:
评论

相关推荐

    ONCRPC.rar_ONCRPC_code rpc_onc_onc rpc

    这个"ONCRPC.rar_ONCRPC_code rpc_onc_onc rpc"文件包含的是关于ONC RPC协议的实现代码,主要针对的是JAVA平台,旨在实现不同编程语言之间的RPC调用。 在RPC(Remote Procedure Call)机制中,客户端可以透明地调用...

    oncrpc.rar_RPC. VC++_oncrpc windows_windows RPC_ycnian的博客

    RPC(Remote Procedure Call)是一种分布式计算技术,允许一个程序在一台计算机上执行远程操作,就像它在本地执行一样。在Windows环境下,RPC是系统服务的重要组成部分,广泛用于进程间通信和系统组件之间的交互。本...

    jsonrpc-frontend:前端应用程序发送 json-rpc 请求进行测试

    JSON-RPC(JavaScript Object Notation Remote Procedure Call)是一种轻量级的远程过程调用协议,常用于客户端-服务器通信,特别是在Web应用中。它利用JSON作为数据交换格式,因为JSON易于阅读、编写,并且对机器...

    jsonrpc-c-master 基于 json rpc 1.0 纯C开发的服务端代码和示例

    JSON-RPC(JavaScript Object Notation Remote Procedure Call)是一种轻量级的远程过程调用协议,它使用JSON(JavaScript Object Notation)作为数据交换格式。基于JSON-RPC 1.0的C语言实现,如"jsonrpc-c-master...

    rpc远程调用库C语言实现

    RPC(Remote Procedure Call)是一种进程间通信技术,允许在一台计算机上的程序调用另一台计算机上的程序,使得分布式系统能够像调用本地函数一样调用远程服务。在本主题中,我们将深入探讨如何使用C语言实现RPC,并...

    android-json-rpc

    JSON-RPC(JavaScript Object Notation Remote Procedure Call)是一种轻量级的远程过程调用协议,常用于客户端-服务器通信。在Android开发中,有时我们需要与远程服务器进行数据交互,这时JSON-RPC客户端库就显得尤...

    Java RPC调用示例

    Java RPC(Remote Procedure Call)调用是分布式系统中常见的通信方式,它允许一个程序在不关心远程系统具体实现的情况下调用另一个网络上的程序。在这个Java RPC调用示例中,我们将探讨RPC的基本概念、实现机制以及...

    手写rpc rpc简单源码 rpc源码学习 rpc过程了解 rpc通信原理

    RPC(Remote Procedure Call)远程过程调用是一种计算机通信协议,允许程序在一台计算机上执行另一台计算机上的程序,而无需了解底层网络协议的细节。它为开发者提供了一种透明调用远程服务的方式,使得分布式系统...

    影像RPC和GCP校正

    在IT行业中,"影像RPC和GCP校正"是一个重要的图像处理领域,主要涉及遥感图像的几何校正。遥感图像(Remote Sensing Image,简称RSI)由于拍摄角度、大气条件、传感器特性等因素,往往存在几何畸变,需要进行校正以...

    javax.xml.rpc

    "javax.xml.rpc"是Java平台中的一个关键组件,主要用于实现基于XML的远程过程调用(XML-RPC)服务。这个框架允许Java应用程序通过HTTP协议来调用远程服务器上的方法,从而实现分布式计算。在Java EE环境中,它常与...

    基于严格成像模型的遥感影像RPC参数求解.pdf

    基于严格成像模型的遥感影像RPC参数求解 本文主要讨论基于严格成像模型的遥感影像RPC参数求解问题。RPC参数是遥感影像几何校正的关键参数,通过严格成像模型可以推导出RPC参数。文中首先介绍了基于严格成像模型的...

    Netty4.1实战-手写RPC框架.pdf

    RPC是一种远程调用的通信协议,例如dubbo、thrift等,我们在互联网高并发应用开发时候都会使用到类似的服务。本专题主要通过三个章节实现一个rpc通信的基础功能,来学习RPC服务中间件是如何开发和使用。章节内以源码...

    实现一个简单的RPC框架

    RPC(Remote Procedure Call)是一种进程间通信的技术,它允许程序在不同的网络节点上进行通信,就像调用本地函数一样调用远程系统上的函数或方法。本篇将详细讲解如何使用socket、反射和序列化等技术来实现一个简单...

    解决 RPC服务 属性按钮全部都是灰色

    RPC 服务属性按钮全部都是灰色的解决方案 解决 RPC 服务属性按钮全部都是灰色的问题是很严重的问题,但可以解决。本文将详细介绍 RPC 服务属性按钮全部都是灰色的原因和解决方案,包括手动启动“远程过程调用”服务...

    RPC(远程过程调用)

    RPC(Remote Procedure Call)是一种计算机通信协议,它允许程序在分布式环境中的一个系统上执行另一系统上的函数或方法,就像是本地调用一样。这个过程涉及到了客户端、服务器端和服务调用的封装,使得开发者无需...

    rpc.rstatd-4.0.1.tar.gz

    linux使用,使用教程 linux下安装rpc.rstatd 1.rpc服务需rsh的支持,一般情况下rsh已安装。rpm -qa rsh查看。 2.右键另存为http://heanet.dl.sourceforge.net/sourceforge/rstatd/rpc.rstatd-4.0.1.tar.gz下载rpc....

    RPC.rar_C++ 远程调用_VC6.0 开发RPC_windows RPC_远程过程调用

    RPC,即Remote Procedure Call(远程过程调用),是计算机网络编程中的一个重要概念,它允许一个程序在不理解底层网络协议的情况下,调用另一个网络上不同机器上的程序。在这个"RPC.rar"压缩包中,主要围绕C++语言在...

    ENVI自定义RPC文件图像正射校正及数据

    2. **创建RPC模型**:在ENVI主界面中,选择“Tools” -> “RPC Correction”,进入RPC校正对话框。点击“Load”按钮,导入RPC文件。ENVI会自动读取并建立RPC模型。 3. **设置输出参数**:在对话框中,指定输出文件...

    高性能RPC框架 nfs-rpc

    RPC(Remote Procedure Call)是一种进程间通信机制,它允许一个程序调用另一个位于不同系统上的程序,就像调用本地函数一样。NFS-RPC(Network File System - Remote Procedure Call)是基于RPC的一种特定应用,...

    安装打印机时RPC服务器不可用的解决

    ### 安装打印机时RPC服务器不可用的问题及解决方法 #### 问题背景 在尝试安装网络打印机或连接至网络打印机时,用户可能会遇到一个错误提示:“RPC(远程过程调用)服务器不可用”。这一错误通常发生在Windows操作...

Global site tag (gtag.js) - Google Analytics