远程过程调用,简称为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. Nginx 反向代理 负载均衡 虚拟主机

    Nginx 反向代理 负载均衡 虚拟主机配置 通过本章你将学会利用Nginx配置多台虚拟主机,清楚代理服务器的作用,区分正向代理和反向代理的区别,搭建使用Nginx反向搭理和负载均衡,了解Nginx常 ...

  2. nginx 容器反向代理网址的设置

    先讲一下场景:  nginx 容器要和SpringBoot 容器部署在一台机器上, nginx 为 SpringBoot 提供反向代理, 需要在 nginx.conf 中写上 SpringBoot 的 ...

  3. Linux下批量杀掉 包含某个关键字的 程序进程

    有时候因为一些情况,需要把 linux 下符合某一项条件的所有进程 kill 掉,又不能用 killall 直接杀掉某一进程名称包含的所有运行中进程(我们可能只需要杀掉其中的某一类或运行指定参数命令的 ...

  4. “短路求值(Short-Circuit Evaluation)

        // 逻辑与和逻辑或操作符总是先计算其做操作数,只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数. function aa() { if (null) { console ...

  5. Request method 'POST' not supported解决办法

    (1)考虑拦截器是否将该链接拦截

  6. 贯穿RobotFramework框架 - 关键字(一) 最全面的疏理

    在RF中,关键字是一个非常重要的存在.想做任何事情,都是通过关键字来实现的. 这篇文章对RobotFramework中的关键字做个整理.大概分为以下几点内容: 1.什么是关键字 2.关键字来自哪里.有 ...

  7. spring cloud--zuul网关和zuul请求过滤

    这里仍然以Windows和jdk为运行环境,按照下面的步骤打包-运行-访问就能看到效果.启动项目jar包: java -jar F:\jars-zuul\register-0.0.1-SNAPSHOT ...

  8. jenkins主要目录用途

    主目录 除了Jenkins的WAR包所在目录,Jenkins还有一个更重要的目录——Jenkins的所有重要数据都存放在这个独立的目录中,称为Jenkins主目录,它的默认位置是在当前用户根目录的隐藏 ...

  9. 二、vue之 使用vscode配置

    vue之 使用vscode配置 visual  studio code 简称vscode,下图为图标 ... 开启vscode ... 1.导入文件夹,选择菜单栏 文件-打开文件夹->选择相应已 ...

  10. GIt -- fatal: refusing to merge unrelated histories 问题处理

    今晚碰到这个问题-- fatal: refusing to merge unrelated histories 想了一下,为什么就这样了? 因为我是先本地创建了仓库,并添加了文件,然后再到github ...