zoukankan      html  css  js  c++  java
  • Golang中的RPC(转载)

    1. RPC 简介

      1. 远程过程调用(Remote Procedure Call,缩写为 RPC)
      2. 可以将一些比较通用的场景抽象成微服务,然后供其他系统远程调用
      3. RPC 可以基于HTTP协议 也可以基于TCP协议,基于HTTP协议的RPC像是我们访问网页一样(GET/POST/PUT/DELETE/UPDATE),大部分的RPC都是基于TPC协议的(因为基于传输层,效率稍高一些)
      4. 基于TCP 的 RPC 工作过程
        1. 客户端对请求的对象序列化
        2. 客户端连接服务端,并将序列化的对象通过socket 传输给服务端,并等待接收服务端的响应
        3. 服务端收到请求对象后将其反序列化还原客户端的对象
        4. 服务端从请求对象中获取到请求的参数,然后执行对应的方法,得到返回结果
        5. 服务端将其结果序列化并传给客户端,客户端得到响应结果对象后将其反序列化,得到响应结果
    2. Golang中的RPC 注:例子参考 golang实现RPC的几种方式

      1. net/rpc库

        注:没办法在其他语言中调用上面例子实现的RPC方法

        1. 服务端 rpc_server.go

          package main
          import (
            "errors"
            "fmt"
            "log"
            "net"
            "net/http"
            "net/rpc"
            "os"
          )
          // 算数运算结构体
          type Arith struct {
          }
          
          type AirthRequest struct {
            A int
            B int
          }
          
          // 算数运算请求结构体
          type AirthResponse struct {
            Pro int // 成绩
            Quo int // 商
            Rem int // 余数
          }
          
          // 乘法运算方法
          func (this *Arith) Multiply(req AirthRequest, res *AirthResponse) error {
            res.Pro = req.A * req.B
            return nil
          }
          
          // 除法运算
          func (this *Arith) Divide(req AirthRequest, res *AirthResponse) error {
            if req.B == 0 {
              return errors.New("divide by zero")
            }
            res.Quo = req.A / req.B
            res.Rem = req.A % req.B
            return nil
          }
          
          func main() {
            rpc.Register(new(Arith))	// 注册rpc服务
            rpc.HandleHTTP()				//采用http协议作为rpc载体
            lis, err := net.Listen("tcp", "127.0.0.1:8905")
            if err != nil {
              log.Fatalln("fatal error:", err)
            }
            fmt.Println(os.Stdout, "%s", "start connect
          ")
            http.Serve(lis, nil)
          }
          
          
        2. 客户端 rpc_client.go

          package main
          
          import (
          	"fmt"
          	"log"
          	"net/rpc"
          )
          
          // 运算请求结构体
          type AirthRequest struct {
          	A int
          	B int
          }
          
          // 运算响应结构体
          type AirthResponse struct {
          	Pro int // 乘积
          	Quo int // 商
          	Rem int // 余数
          }
          
          func main() {
          	conn, err := rpc.DialHTTP("tcp", "127.0.0.1:8905")
          	if err != nil {
          		log.Fatalln("dialing error:", err)
          	}
          	req := AirthRequest{10, 2}
          	var res AirthResponse
          	err = conn.Call("Arith.Multiply", req, &res)
          
          	if err != nil {
          		log.Fatalln("arith error:", err)
          	}
          	fmt.Println("%d * %d = %d
          ", req.A, req.B, res.Pro)
          	err = conn.Call("Arith.Divide", req, &res)
          	if err != nil {
          		log.Fatal("arith error:", err)
          	}
          	fmt.Printf("%d / %d, quo is %d, rem is %d
          ", req.A, req.B, res.Quo, res.Rem)
          }
          
          
      2. net/rpc/jsonrpc库

        注:支持跨语言调用

        1. jsonrpc_server.go

          package main
          
          import (
              "errors"
              "fmt"
              "log"
              "net"
              "net/rpc"
              "net/rpc/jsonrpc"
              "os"
          )
          
          // 算数运算结构体
          type Arith struct {
          }
          
          // 算数运算请求结构体
          type ArithRequest struct {
              A int
              B int
          }
          
          // 算数运算响应结构体
          type ArithResponse struct {
              Pro int // 乘积
              Quo int // 商
              Rem int // 余数
          }
          
          // 乘法运算方法
          func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
              res.Pro = req.A * req.B
              return nil
          }
          
          // 除法运算方法
          func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
              if req.B == 0 {
                  return errors.New("divide by zero")
              }
              res.Quo = req.A / req.B
              res.Rem = req.A % req.B
              return nil
          }
          
          func main() {
              rpc.Register(new(Arith)) // 注册rpc服务
          
              lis, err := net.Listen("tcp", "127.0.0.1:8096")
              if err != nil {
                  log.Fatalln("fatal error: ", err)
              }
          
              fmt.Fprintf(os.Stdout, "%s", "start connection")
          
              for {
                  conn, err := lis.Accept() // 接收客户端连接请求
                  if err != nil {
                      continue
                  }
          
                  go func(conn net.Conn) { // 并发处理客户端请求
                      fmt.Fprintf(os.Stdout, "%s", "new client in coming
          ")
                      jsonrpc.ServeConn(conn)
                  }(conn)
              }
          }
          
        2. jsonrpc_client.go

          package main
          
          import (
              "fmt"
              "log"
              "net/rpc/jsonrpc"
          )
          
          // 算数运算请求结构体
          type ArithRequest struct {
              A int
              B int
          }
          
          // 算数运算响应结构体
          type ArithResponse struct {
              Pro int // 乘积
              Quo int // 商
              Rem int // 余数
          }
          
          func main() {
              conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8096")
              if err != nil {
                  log.Fatalln("dailing error: ", err)
              }
          
              req := ArithRequest{9, 2}
              var res ArithResponse
          
              err = conn.Call("Arith.Multiply", req, &res) // 乘法运算
              if err != nil {
                  log.Fatalln("arith error: ", err)
              }
              fmt.Printf("%d * %d = %d
          ", req.A, req.B, res.Pro)
          
              err = conn.Call("Arith.Divide", req, &res)
              if err != nil {
                  log.Fatalln("arith error: ", err)
              }
              fmt.Printf("%d / %d, quo is %d, rem is %d
          ", req.A, req.B, res.Quo, res.Rem)
          }
          

    GitHub: https://github.com/zhuchenglin/gorpc

  • 相关阅读:
    Odoo Entypo Regular Icon List
    Ubuntu 循环遍历当前目录下所有文本文件中的字符
    FairyGUI学习
    FairyGUI和NGUI对比
    热更新有多重要?游戏代码热更新杂谈
    收藏的链接
    Vuforia AR实战教程
    BleedTree动画混合树
    Unity3d导出安卓版本
    Unity+高通Vuforia SDK——AR
  • 原文地址:https://www.cnblogs.com/zhuchenglin/p/13172984.html
Copyright © 2011-2022 走看看