聊聊RPC及其原理
什么是RPC? RPC是Remote Procedure Call的缩写,像Client-Servier一样的远程过程调用,也就是调用远程服务就跟调用本地服务一样方便,一般用于将程序部署在不同的机器上,供客户端进行调用。就像一个request-response调用系统一样简单。在面向对象编程的程序中,RPC也可以用Remote method invocation(RMI)来展现。为什么用它呢,因为随着分布式结构的普遍,越来越多的应用需要解耦,将不同的独立功能部署发布成不同的服务供调用。
它的主要流程是Client -> Client Stub -> Network -> Server Stub -> Server 执行完成之后再进行返回。
这里边比较重要的就是Clint Stub和Server Stub,他们主要的作用就是将调用的方法和参数进行编码(Marshalling)序列化,将序列化后的数据通过网络发送给Server Stub,然后等待Server回执。Server Stub将受到的序列化字节进行解码(Unmarshaling)反序列化,然后再将参数传入到对应到的方法中执行,将得出的结果计算出来之后再进行返回,返回的过程和正向的过程类似。
那么这个结构里边的内容这么复杂,而且还需要保证数据的完整,网络等因素,所以这块有一个通讯的标准就是IDL(Interface Description Language)接口定义语言,因为很多程序采用了不同的编程语言(Java,C, C++ etc.)和不同的操作系统(Windows, CentOs, RHEL etc.),要保证数据能够正常通讯,并且不受语言和操作系统等限制,就有了它。比如Apache的Thrift 、Avro和Google的 Protocol Buffers、阿里的Dubbo等。
其实很多人早已经应用了它了,但是可能不知道,比如web service的WSDL。下面我就用一个小程序来创建一个简单基于的WSDL的RPC。使用JDK的JAX-WS实现
接口类(定义了一个非常简单的方法):
package com.hqs.rpc; import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style; /**
* 接口
* @author hqs
*
*/
@WebService
@SOAPBinding(style = Style.RPC)
public interface IRPCService {
@WebMethod
public String RPCMethod(String str);
}
实现类:
package com.hqs.rpc; import javax.jws.WebService; /**
* 实现类
* @author hqs
*
*/
@WebService (endpointInterface = "com.hqs.rpc.IRPCService")
public class RPCServiceImpl implements IRPCService { @Override
public String RPCMethod(String str) {
System.out.println("service received:" + str);
return "RPC Method invoked: " + str;
} }
服务发布类:
package com.hqs.rpc; import javax.xml.ws.Endpoint; /**
* 发布类
* @author hqs
*
*/
public class RPCPublisher {
public static void main(String[] args) {
//自己定义地址
Endpoint.publish("http://localhost:9966/rpc", new RPCServiceImpl());
}
}
这个时候启动服务类,然后就可以通过地址http://localhost:9966/rpc?wsdl访问WSDL文件了了:
<?xml version="1.0" encoding="UTF-8"?> <!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --> <!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --> -<definitions name="RPCServiceImplService" targetNamespace="http://rpc.hqs.com/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://rpc.hqs.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <types/> -<message name="RPCMethod"> <part type="xsd:string" name="arg0"/> </message> -<message name="RPCMethodResponse"> <part type="xsd:string" name="return"/> </message> -<portType name="IRPCService"> -<operation name="RPCMethod"> <input message="tns:RPCMethod" wsam:Action="http://rpc.hqs.com/IRPCService/RPCMethodRequest"/> <output message="tns:RPCMethodResponse" wsam:Action="http://rpc.hqs.com/IRPCService/RPCMethodResponse"/> </operation> </portType> -<binding type="tns:IRPCService" name="RPCServiceImplPortBinding"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> -<operation name="RPCMethod"> <soap:operation soapAction=""/> -<input> <soap:body namespace="http://rpc.hqs.com/" use="literal"/> </input> -<output> <soap:body namespace="http://rpc.hqs.com/" use="literal"/> </output> </operation> </binding> -<service name="RPCServiceImplService"> -<port name="RPCServiceImplPort" binding="tns:RPCServiceImplPortBinding"> <soap:address location="http://localhost:9966/rpc"/> </port> </service> </definitions>
接下来我们就可以写客户端类:
package com.hqs.rpc; import java.net.MalformedURLException;
import java.net.URL; import javax.xml.namespace.QName;
import javax.xml.ws.Service; /**
* 客户端类
* @author hqs
*
*/
public class RPCClient {
public static void main(String[] args) {
try {
URL url = new URL("http://localhost:9966/rpc?wsdl");
QName qname = new QName("http://rpc.hqs.com/","RPCServiceImplService");
Service service = Service.create(url, qname);
IRPCService irpc = service.getPort(IRPCService.class);
System.out.println(irpc.RPCMethod("client"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
} RPC Method invoked: client
简单的RPC就这么实现了。其实目前实现上一些公司实现的比较复杂,分为服务分为provider和consumer,以及负责监控管理的provider,provider一般采用zookeeper单数集群,用于管理和监控provider的服务注册,因为provider可能部署在同一台机器上的不同端口或者不同机器上,consumer通过zookeeper就可以拿到provider的IP/接口/版本号/端口等信息,然后进行调用。
好了,如果有不对的地方,请大家指正。
聊聊RPC及其原理的更多相关文章
- RPC实现原理(HSF、dubbo) 从头开始(一)
前言 阔别了很久博客园,虽然看了以前写的很多东西感觉好幼稚,但是还是觉得应该把一些自己觉得有用的东西和大家分享.废话不多说,现在开始进入正题. 之前的六年工作经验,呆过了一些大公司,每个在大公司呆过的 ...
- 网络编程 -- RPC实现原理 -- 目录
-- 啦啦啦 -- 网络编程 -- RPC实现原理 -- NIO单线程 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V1 网络编程 -- RPC实现原理 -- NIO多线程 -- ...
- 网络编程 -- RPC实现原理 -- NIO单线程
网络编程 -- RPC实现原理 -- 目录 啦啦啦 Class : Service package lime.pri.limeNio.optimize.socket; import java.io.B ...
- 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V1
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——设置标识变量selectionKey.attach(true);只处理一次(会一直循环遍历selectionKeys,占用CPU资源). ( ...
- 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V2
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——增加WriteQueue队列,存放selectionKey.addWriteEventToQueue()添加selectionKey并唤醒阻 ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V1 -- 入门应用
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——Netty入门应用 Class : NIOServerBootStrap package lime.pri.limeNio.netty.ne ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V2 -- 对象传输
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- 使用序列化和反序列化在网络上传输对象:需要实现 java.io.Serializable 接口 只能传输( ByteBuf ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V3 -- 编码解码
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- pipeline.addLast(io.netty.handler.codec.MessageToMessageCodec ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V4 -- 粘包拆包
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- new LengthFieldPrepender(2) : 设置数据包 2 字节的特征码 new LengthFieldB ...
随机推荐
- 【小程序】微信小程序实现各种特效实例
写在前面 最近在负责一个微信小程序的前端以及前后端接口的对接的项目,整体上所有页面的布局我都已经搭建完成,里面有一些常用的特效,总结一下,希望对大家和我都能有所帮助 实例1:滚动tab选项卡 先看一下 ...
- 用 Python 撸一个区块链
本文翻译自 Daniel van Flymen 的文章 Learn Blockchains by Building One 略有删改.原文地址:https://hackernoon.com/learn ...
- Win7 32位系统下Sublime text 3的安装以及配置C/C++、java、python的开发环境方法
本人初学者,此文仅是对这几天鼓捣subime text 3一点微不足道的经验总结,如有明显错误,欢迎指正! 好了,废话少说,进入正题,之前编程java一直用的是eclipse,java的主流IDE,后 ...
- 我的第一个python web开发框架(5)——开发前准备工作(了解编码前需要知道的一些常识)
中午吃饭时间到了,小白赶紧向老菜坐的位置走过去. 小白:老大,中午请你吃饭. 老菜:哈哈...又遇到问题了吧,这次得狠狠宰你一顿才行. 小白:行行行,只要您赏脸,米饭任吃,嘻嘻,我们边走边聊. ... ...
- 在Kubernetes集群中使用calico做网络驱动的配置方法
参考calico官网:http://docs.projectcalico.org/v2.0/getting-started/kubernetes/installation/hosted/kubeadm ...
- riot.js教程【二】组件撰写准则、预处理器、标签样式和装配方法
基本要求 一个riot标签,就是展现和逻辑的组合(也就是html和JS): 以下是编写riot标签最基本的规则: 先撰写HTML,再撰写JS,JS代码可以写在<script>标签内部,但这 ...
- 吾八哥学Python(六):运算符与表达式
上篇简单学习了数学运算符,今天来学习下完整的Python运算符与表达式,具体看下面的表格吧! 表1 运算符与它们的用法 运算符 名称 说明 例子 + 加 两个对象相加 3 + 5得到8.’a’ + ‘ ...
- Opencv基础课必须掌握:滑动条做调色盘 -OpenCV步步精深
滑动条做调色盘 我们来想一下这个程序需要什么,首先需要一个窗口显示一切=.=(︿( ̄︶ ̄)︿废话一样): 说到调色盘除了画板也就是窗口(默认为黑色),调色就要涉及三种颜色 红色Red(我们用R表示), ...
- python第五课——自定义线程池
内容概要: 1.low版线程池 2.绝版线程池 1.low版线程池 设计思路:运用队列queue 将线程类名放入队列中,执行一个就拿一个出来 import queue import threading ...
- 典型的NIO代码
public void selector() throws IOException { ByteBuffer buffer = ByteBuffer.allocate(1024); Selector ...