远程过程调用,简称为RPC,是一个计算机通信协议,它允许运行于一台计算机的程序调用另一台计算机的子程序,而无需额外地为这个交互作用编程。

RPC与传统的HTTP对比

优点:

1. 传输效率高(二进制传输)

2. 发起调用的一方无需知道RPC的具体实现,如同调用本地函数般调用

缺点:

1. 通用性不如HTTP好(HTTP是标准协议)

总结:RPC适合内部服务间的通信调用;HTTP适合面向用户与服务间的通信调用

RPC调用过程如下:

  1. 调用者(客户端Client)以本地调用的方式发起调用;
  2. Client stub(客户端存根)收到调用后,负责将被调用的方法名、参数等打包编码成特定格式的能进行网络传输的消息体;
  3. Client stub将消息体通过网络发送给服务端;
  4. Server stub(服务端存根)收到通过网络接收到消息后按照相应格式进行拆包解码,获取方法名和参数;
  5. Server stub根据方法名和参数进行本地调用;
  6. 被调用者(Server)本地调用执行后将结果返回给server stub;
  7. Server stub将返回值打包编码成消息,并通过网络发送给客户端;
  8. Client stub收到消息后,进行拆包解码,返回给Client;
  9. Client得到本次RPC调用的最终结果。

对于RPC调用流程的实现,抛开调用方与被调用方,其核心主要是:消息协议传输控制的实现

(1). RPC消息协议:客户端调用的参数和服务端的返回值这些在网络上传输的数据以何种方式打包编码和拆包解码

RPC的消息协议在设计时主要要考虑,消息转换及传输的效率,为解决消息转换及传输的效率,可以以二进制的方式传输消息,使用原始的二进制传输可以省去中间转换的环节并减少传输的数据量。

在Python中可以使用struct模块对二进制进行编码和解码:

struct.pact将其它类型转换为二进制,通常用于消息长度的转换:

import struct

# 将整数2转换成适用网络传输的无符号的4个字节整数
>>> struct.pack('!I', 2)
'\x00\x00\x00\x02'

struct.unpack将二进制类型转换为其它类型:

byte_data = '\x00\x00\x00\x02'
# 将2对应的二进制 转换为十进制整数 返回结果是个元组
>>> struct.unpack('!I',byte_data)
(2,)

 (2). RPC传输控制

对于消息数据的传输,主要有HTTP传输和TCP传输,鉴于TCP传输的可靠性,RPC的传输一般使用TCP作为传输协议

在TCP传输中客户端与服务端通过socket进行通信,通信流程:

RPC使用TCP进行传输控制的实现

 import socket

 class Channel(object):
"""
与客户端建立网络连接
""" def __init__(self, host, port):
self.host = host # 服务器地址
self.port = port # 服务器端口 def get_connection(self):
"""
获取一个tcp连接
"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((self.host, self.port))
return sock class Server(object):
def __init__(self, host, port, handlers):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.host = host
self.port = port
self.sock.bind((host, port))
self.handlers = handlers def serve(self):
"""
开启服务器运行,提供RPC服务
"""
# 开启服务监听,等待客户端连接
self.sock.listen(128)
print("开始监听")
while True:
# 接收客户端的连接请求
conn, addr = self.sock.accept()
print("建立连接{}".format(str(addr))) # 创建ServerStub对象,完成客户端具体的RPC调用
stub = ServerStub(conn, self.handlers)
try:
while True:
stub.process()
except EOFError:
# 表示客户端关闭了连接
print("客户端关闭连接")
# 关闭服务端连接
conn.close()

通过Socket使得RPC客户端与服务器进行通信

 TCP服务端
sock = socket.socket() # 创建一个套接字
sock.bind() # 绑定端口
sock.listen() # 监听连接
sock.accept() # 接受新连接
sock.close() # 关闭服务器套接字 TCP客户端
sock = socket.socket() # 创建一个套接字
sock.connect() # 连接远程服务器
sock.recv() # 读
sock.send() # 写
sock.sendall() # 完全写
sock.close() # 关闭

RPC服务的实现:为了能让RPC服务器同时处理多个客户端的请求,提升性能,可以采用多线程、多进程方式实现,下面分别介绍这两种方式实现的RPC服务

多线程RPC服务:

 class ThreadServer(object):
"""
多线程RPC服务器
""" def __init__(self, host, port, handlers):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.host = host
self.port = port
self.sock.bind((host, port))
self.handlers = handlers def serve(self):
"""
开始服务
"""
self.sock.listen(128)
print("开始监听")
while True:
conn, addr = self.sock.accept()
print("建立链接{}".format(str(addr)))
t = threading.Thread(target=self.handle, args=(conn,))
t.start() def handle(self, client):
stub = ServerStub(client, self.handlers)
try:
while True:
stub.process()
except EOFError:
print("客户端关闭连接") client.close()

多进程RPC服务:

 class MultiProcessServer(object):
"""
多进程服务器
""" def __init__(self, host, port, handlers):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.host = host
self.port = port
self.sock.bind((host, port))
self.handlers = handlers def serve(self):
"""
开始服务
"""
self.sock.listen(128)
print("开始监听")
while True:
conn, addr = self.sock.accept()
print("建立链接{}".format(str(addr)))
t = Process(target=self.handle, args=(conn,))
t.start() def handle(self, client):
stub = ServerStub(client, self.handlers)
try:
while True:
stub.process()
except EOFError:
print("客户端关闭连接") client.close()

RPC原理及其调用过程的更多相关文章

  1. RPC框架调用过程详解

    RPC框架调用过程详解 2017年09月16日 21:14:08 荷叶清泉 阅读数 6275   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

  2. rpc调用过程

    在openstack中,各个组件之间的调用遵循RESTful风格,而组件内部各服务之间的相互调用采用rpc远程调用,比如nova-conductor和nova-compute rpc原理: 首先了解什 ...

  3. go微服务框架go-micro深度学习(四) rpc方法调用过程详解

    上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取server的地 ...

  4. go微服务框架go-micro深度学习 rpc方法调用过程详解

    摘要: 上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取serv ...

  5. java多态的实现原理(JVM调用过程)(综合多篇文章,参考见文末)

    一个对象变量可以指示多种实际类型的现象称为多态 允许不同类的对象对同一消息做出响应.方法的重载.类的覆盖正体现了多态. 1.多态的机制 1.1 本质上多态分两种 1.编译时多态(又称静态多态) 2.运 ...

  6. Openstack Nova 源码分析 — RPC 远程调用过程

    目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...

  7. Hbase的WAL在RegionServer基本调用过程

    版权声明:本文由熊训德原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/221 来源:腾云阁 https://www.qclo ...

  8. 你应该知道的RPC原理

    你应该知道的RPC原理 在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司尤其是大型互 ...

  9. RPC原理解析

    1.RPC原理解析 1.1 什么是RPC RPC(Remote Procedure Call Protocol) --远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络 ...

随机推荐

  1. Druid.jar包

    首先了解一下,什么是Druid. Druid是Java语言中最好的数据库连接池,它能够提供强大的监控和扩展功能. Druid是一个JDBC组件,它包括三部分: 1)DruidDriver 代理Driv ...

  2. 2017-12-20python全栈9期第五天第二节之字典的增删查改和字典的for循环

    #!/user/bin/python# -*- coding:utf-8 -*-dic1 = {'age':24,'name':'zd','sex':'boy'}print(dic1)#增dic1[' ...

  3. Springboot集成FreeMarker

    Apache官网对FreeMarker的解释如下: Apache FreeMarker™是一个模板引擎 :一个基于模板和变化的数据来生成文本输出(HTML网页,电子邮件,配置文件,源代码,等等)的Ja ...

  4. OA系统开发人事模块关于请假跨月的处理

    前言:其实对于跨月的数据单独处理是不难的,但是对于后台显示页面,肯定不是单纯拼接一个where条件的,因此在我的项目也是如此,并不能够用普遍的方法来处理,此时就想尽量用简单的方法来处理跨月数据的准确性 ...

  5. 基于jeesite的cms系统(四):使用Beetl模版引擎在后端渲染数据

    一.Beetl简介 1. 什么是Beetl Beetl目前版本是2.9.3,相对于其他java模板引擎,具有功能齐全,语法直观,性能超高,以及编写的模板容易维护等特点.使得开发和维护模板有很好的体验. ...

  6. Koa与Node.js开发实战(1)——Koa安装搭建(视频演示)

    学习架构: 由于Koa2已经支持ES6及更高版本,包括支持async方法,所以请读者保证Node.js版本在7.6.0以上.如果需要在低于7.6的版本中应用Koa的async方法,建议使用Babel ...

  7. 扩展欧几里得(exgcd)与同余详解

    exgcd入门以及同余基础 gcd,欧几里得的智慧结晶,信息竞赛的重要算法,数论的...(编不下去了 讲exgcd之前,我们先普及一下同余的性质: 若,那么 若,,且p1,p2互质, 有了这三个式子, ...

  8. SpringMVC整合Mybatis的流程

    前提:如何要整合SpringMVC 与Mybatis,首先要会配置SpringMVC 第一部分:配置SpringMVC 第一步:导入jar包 第二步:构建一个请求 <%@ page langua ...

  9. jQuery循环遍历取值

    1:循环遍历取值 var arr = new Array(); $(".plus-tag a span").each(function(i) { arr[i] = $(this). ...

  10. spring cloud 集群健康监控--turbine-dashboard仪表盘

    这里仍然以Windows和jdk为运行环境,按照下面的步骤打包-运行-访问就能看到效果. 运维健康监控--hystrix-dashboard仪表盘 java -jar F:\jars-dashboar ...