`

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
分享到:
评论

相关推荐

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

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

    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....

    jsonrpc4j+springboot+maven实例

    <artifactId>jsonrpc4j <version>1.5.0 <groupId>javax.portlet <artifactId>portlet-api <version>2.0 Service代码: @JsonRpcService("/member") public interface MemberService { ... } 因为是基于...

    ONCRPC.rar_ONCRPC_code rpc_onc_onc rpc

    ONC RPC 协议实现,根据.x接口文档生成JAVA代码,实现不同语言间的RPC调用

    RPC-client异步收发核心细节

    异步回调和同步回调相比,除了序列化组件和连接池组件,会多...异步回调能提高系统整体的吞吐量,具体使用哪种方式实现RPC-client,可以结合业务场景来选取(对时延敏感的可以选用同步,对吞吐量敏感的可以选用异步)。

    C语言头文件 RPC C语言头文件 RPC

    C语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC...RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPC

    基于Actor模型的RPC

    2、使用Netty进行通讯(同节点RPC不走网络,直接入收件箱队列); 3、路由策略:随机路由、指定Key路由、资源Id路由、强制路由 4、使用ZK进行集群状态管理 备注: 1、使用自定义注解进行服务注册及辅助控制(线程...

    json-rpc.jar 和 jsonrpc.js

    JSON-RPC-Java是一个用Java来实现动态JSON-RPC的框架. 利用它内置的一个轻级量JSON-RPC JavaScripIt客户端,可以让你透明地在JavaScript中调用Java代码。JSON-RPC-Java可运行在Servlet容器中如Tomcat也可以运行在...

    百兆以太网芯片RPC8201F百兆PHY芯片,替换RTL8201,替换裕太YT8510

    The RPC8201F is a single-chip/single-port 10/100Mbps Ethernet PHY transceiver that supports: • MII (Media Independent Interface) • RMII (Reduced Media Independent Interface) The RPC8201F implements ...

    jsonrpc是一个基于Java的高性能开源RPC框架

    jsonrpc是一个基于Java的高性能开源RPC框架

    RPC框架的实现原理,及RPC架构组件详解.pdf

    详细讲解RPC

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

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

    jemeter支持rpc插件jar包

    此插件支持在jmeter中以rpc方式对dubbo接口进行调用、rpc方式调用dubbo,解压包后里面有两个文件,一个是支持rpc的插件,另一个赠送idea中对数据库访问的插件 插件名称:jmeter-plugins-dubbo-2.7.7-jar-with-...

    JSON-RPC-Java实例

    JSON-RPC-Java是一个用Java来实现动态JSON-RPC的框架. 利用它内置的一个轻级量JSON-RPC JavaScripIt客户端,可以让你透明地在JavaScript中调用Java代码。JSON-RPC-Java可运行在Servlet容器中如Tomcat也可以运行在...

    拍拍贷微服务rpc框架源码.zip

    拍拍贷微服务rpc框架源码.zip # 拍拍贷微服务体系 拍拍贷微服务体系是拍拍贷基础框架部总结内部微服务多年实践,参考、吸收大量业内解决方案形成的适合中型互联网公司的微服务解决方案。 拍拍贷微服务体系主要组成...

    android-json-rpc

    android-json-rpc是一个在android程序中使用的JSON-RPC客户端类库。它提供了一个简单的API来执行JSON-RPC服务调用

    自定义rpc思路设计

    自定义rpc框架 ,用到了nettty zookeeper等等,模仿dubbo

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

    rpc远程过程调用的手写简单源码 学习rpc通信的可以下载下来看看 很有帮助 包括客户端和服务端的网络调用 通信 序列化....等等

    JsonRpc-Cpp

    JsonRpc-Cpp - JSON-RPC implementation. * Copyright (C) 2008-2011 Sebastien Vincent * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser ...

Global site tag (gtag.js) - Google Analytics