zoukankan      html  css  js  c++  java
  • RPC简介与实践

      本文是RPC的简介与实践,首先介绍一下RPC的概念与原理,接着介绍一下Go语言对RPC的支持,最后提供一个Go语言原生RPC的简单demo。

    一、RPC是什么

      RPC,全称:Remote Procedure Call,中文翻译:远程过程调用。

      RPC是一种技术思想,而非规范或协议,它指的是,本地计算机程序通过网络向远程计算机程序请求服务,隐藏底层网络技术,使其看起来就像调用本地函数一样简便,服务提供方与调用方都无需了解底层网络的传输细节。

    二、RPC是怎么工作的

    1. RPC框架的组成

    (1)客户端(Client):服务调用者。

    (2)服务端(Server):服务提供者。

    (3)客户端存根(Client Stub):存放服务端的地址信息,负责将客户端的请求参数打包成网络消息,通过网络远程发送给服务方。

    (4)服务端存根(Server Stub):接收调用方发送过来的消息,将消息解包,并调用本地的方法。

    (5)底层网络传输:可以是TCP或HTTP。

    2. 一次完整的RPC调用流程

    简单图示:

    详细介绍:

    (1)客户端通过本地调用的方式调用服务。

    (2)客户端存根接收到调用请求后负责将调用的方法、参数等信息序列化成网络消息体,找到远程服务的地址,将消息通过网络发送给服务方。

    (3)服务端存根接收到消息后进行解码(反序列化),根据解码结果调用本地服务。

    (4)服务端调用本地方法进行业务逻辑处理,然后将处理结果返回给服务端存根。

    (5)服务端存根将调用结果序列化,然后通过网络发送给调用方。

    (6)客户端存根收到消息,将消息进行解码(方序列化),得到调用结果,将结果发送给客户端。

    (7)客户端最终得到服务调用结果。

    三、Go语言对RPC的支持

    1. Go内置RPC

      Go标准包“net/rpc”中已经提供了对RPC的支持,而且支持三个级别的RPC:TCP、HTTP、JSONRPC。但Go的RPC只支持Go开发的服务器与客户端之间的交互,无法跨语言调用,因为在内部,它们采用了Gob编码。

    2. 什么是Gob编码

      Gob是Go语言内置的编解码方式,可以支持变长类型的编解码(意味着通用)而且它的效率比json,xml更高。

    3. Go的RPC函数怎么写

      Go RPC函数只有符合下面的条件才能被远程访问,否则会被忽略:

    (1)函数必须是导出的(函数名称首字母大写)。

    (2)必须有两个导出类型的参数,第一个是接收的参数,第二个是返回给客户端的参数,第二个参数必须是指针类型的。

    (3)必须有一个error类型的返回值。

    4. 一个简单的demo

      这里提供一个基于TCP的RPC简单demo,逻辑很简单,就是求两个整型数值的乘机与商余,代码如下。

    (1)服务端:

    /**
    * rpc demo tcp server - 求两数的乘积与商余
    * author: JetWu
    * date: 2020.04.21
     */
    package main
    
    import (
    	"errors"
    	"fmt"
    	"log"
    	"net"
    	"net/rpc"
    	"time"
    )
    
    //接收参数
    type Args struct {
    	A, B int
    }
    
    //返回参数
    type Quotient struct {
    	Quo, Rem int
    }
    
    //RPC服务函数
    
    type Arith int
    
    func (t *Arith) Multiply(args *Args, reply *int) error {
    	*reply = args.A * args.B
    	return nil
    }
    
    func (t *Arith) Divide(args *Args, quo *Quotient) error {
    	if args.B == 0 {
    		return errors.New("divide by zero")
    	}
    	quo.Quo = args.A / args.B
    	quo.Rem = args.A % args.B
    	return nil
    }
    
    func main() {
    	//RPC服务注册
    	arith := new(Arith)
    	rpc.Register(arith)
    
    	tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
    	if err != nil {
    		log.Fatal("net.ResolveTCPAddr err: ", err)
    	}
    	//监听网络
    	listener, err := net.ListenTCP("tcp", tcpAddr)
    	if err != nil {
    		log.Fatal("net.ListenTCP err: ", err)
    	}
    	defer listener.Close()
    	log.Println("rpc demo tcp server started ...")
    
    	for {
    		fmt.Printf("accepted at %v
    ", time.Now())
    		//等待客户端连接
    		conn, err := listener.Accept()
    		if err != nil {
    			fmt.Println("listener.Accept err: ", err)
    			continue
    		}
    		fmt.Printf("getted at %v
    ", time.Now())
    		//为客户端提供服务
    		go rpc.ServeConn(conn)
    	}
    }
    

    (2)客户端:

    /**
    * rpc demo tcp client - 求两数的乘积与商余
    * author: JetWu
    * date: 2020.04.21
     */
    package main
    
    import (
    	"fmt"
    	"log"
    	"net/rpc"
    )
    
    //接收参数
    type Args struct {
    	A, B int
    }
    
    //返回参数
    type Quotient struct {
    	Quo, Rem int
    }
    
    func main() {
    	//连接服务端
    	client, err := rpc.Dial("tcp", ":1234")
    	if err != nil {
    		log.Fatal("rpc.Dial error: ", err)
    	}
    	log.Println("successfully connected to the rpc demo tcp server ...")
    
    	//RPC服务调用
    
    	args := Args{17, 8}
    	var reply int
    	err = client.Call("Arith.Multiply", args, &reply)
    	if err != nil {
    		log.Fatal("Arith.Multiply error: ", err)
    	}
    	fmt.Printf("Arith.Multiply: %d * %d = %d
    ", args.A, args.B, reply)
    
    	var quo Quotient
    	err = client.Call("Arith.Divide", args, &quo)
    	if err != nil {
    		log.Fatal("Arith.Divide error: ", err)
    	}
    	fmt.Printf("Arith.Divide: %d / %d = %d remainder %d
    ", args.A, args.B, quo.Quo, quo.Rem)
    }
    

      

  • 相关阅读:
    excel的部分使用方法
    liist不同遍历优缺点
    oracle中rownum和rowid的区别
    Oracle中插入100万条数据
    Java中手动提交事务
    oracle 查看表是否存在、包含某字段的表、表是否包含字段
    form的一个特性
    使用oracle的保留字作为字段名称并进行操作的方法
    thinkphp不能够将ueditor中的html文本显示
    java7,java8 中HashMap和ConcurrentHashMap简介
  • 原文地址:https://www.cnblogs.com/wujuntian/p/12829999.html
Copyright © 2011-2022 走看看