今天和大家聊聊golang中怎么使用rpc,rpc数据传输会涉及到gob编码,所以先讲讲gob,别担心,就算你完全没有接触过gob与rpc,只要知道rpc的中文是远程过程调用,剩下的我都能给你讲明白(带你入门不包你精通)!

一、数据结构编码之gob

  gob全称为:Go binary

  Golang自带的一个数据结构序列化编码/解码工具,也就是说gob可以讲go中的一个数据结构序列化成某种东西,还能反序列化!序列化成啥我们后面来看,不管是变成一个字符串,变成二进制流,变成啥先不管,反正作用就是序列化。

  Gob使用时我们需要关注Encoder和Decoder对象,顾名思义,一个是编码的时候用的,一个是解码的时候用的,我们看一下怎么获取这两个对象先:

  所以很明确,需要调用这两个函数来获取Encoder和Decoder对象。注意这里的参数是io.Writer和io.Reader接口类型,我们在上一讲介绍过这两个接口,所以这里需要的参数分别是实现了io.Writer和io.Reader接口类型的对象即可。

  Encoder和Decoder分别有一个主要的方法是:

  看到这里我们已经可以得到如下结论:

  Gob 使用 io.Writer 接口,通过 NewEncoder() 函数创建 Encoder 对象通过调用 Encode()方法实现编码操作;使用 io.Reader 接口,通过 NewDecoder() 函数创建 Decoder 对象并调用 Decode()方法完成解码操作!

  接下来我们试着用一下这个Encoder和Decoder,就轻轻松松入门gob了,来看第一个例子

  例1:数据结构与bytes.Buffer之间的转换(编码成字节切片)

 1package main
2
3import (
4    "bytes"
5    "fmt"
6    "encoding/gob"
7    "io"
8)
9
10//准备编码的数据
11type P struct {
12    X, Y, Z int
13    Name    string
14}
15
16//接收解码结果的结构
17type Q struct {
18    X, Y *int32
19    Name string
20}
21
22func main() {
23    //初始化一个数据
24    data := P{3, 4, 5, "CloudGeek"}
25    //编码后得到buf字节切片
26    buf := encode(data)
27    //用于接收解码数据
28    var q *Q
29    //解码操作
30    q = decode(buf)
31    //"CloudGeek": {3,4}
32    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
33
34}
35
36func encode(data interface{}) *bytes.Buffer {
37    //Buffer类型实现了io.Writer接口
38    var buf bytes.Buffer
39    //得到编码器
40    enc := gob.NewEncoder(&buf)
41    //调用编码器的Encode方法来编码数据data
42    enc.Encode(data)
43    //编码后的结果放在buf中
44    return &buf
45}
46
47func decode(data interface{}) *Q {
48    d := data.(io.Reader)
49    //获取一个解码器,参数需要实现io.Reader接口
50    dec := gob.NewDecoder(d)
51    var q Q
52    //调用解码器的Decode方法将数据解码,用Q类型的q来接收
53    dec.Decode(&q)
54    return &q
55}

  例2:数据结构到文件的序列化和反序列化

 1package main
2
3import (
4    "encoding/gob"
5    "os"
6    "fmt"
7)
8
9//试验用的数据类型
10type Address struct {
11    City    string
12    Country string
13}
14
15//序列化后数据存放的路径
16var filePath string
17
18func main() {
19    filePath = "./address.gob"
20    encode()
21    pa := decode()
22    fmt.Println(*pa) //{Chengdu China}
23}
24
25//将数据序列号后写到文件中
26func encode() {
27    pa := &Address{"Chengdu", "China"}
28    //打开文件,不存在的时候新建
29    file, _ := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0666)
30    defer file.Close()
31
32    //encode后写到这个文件中
33    enc := gob.NewEncoder(file)
34    enc.Encode(pa)
35}
36
37//从文件中读取数据并反序列化
38func decode() *Address {
39    file, _ := os.Open(filePath)
40    defer file.Close()
41
42    var pa Address
43    //decode操作
44    dec := gob.NewDecoder(file)
45    dec.Decode(&pa)
46    return &pa
47}

  上面2个例子都不难,我去掉了错误处理之类的代码,尽量注释了每块代码,耐心看完这2个例子应该就能体会gob的encode和decode精髓了。

理解gob是什么的基础上,如果你需要使用gob开发,建议详细看一下官方文档,了解一下更多的细节:https://golang.org/pkg/encoding/gob/

二、golang中的rpc入门

  如果你之前没有做过基于rpc通信的开发工作,直接去网上查rpc相关的知识点的时候很可能会一脸蒙圈,rest api咋就那么好理解,一个http请求过去就行了,rpc咋个回事,看不懂呀。。。

  所以我不会和多数教程一样为了追求详细或者展示自己技术多牛而去写很长的例子,扯一堆专业的概念,我们先最快的方式体验一下rpc调用的感觉!

  rpc服务端

 1package main
2
3import (
4    "net"
5    "net/rpc"
6    "net/http"
7)
8
9type Args struct {
10    A, B int
11}
12
13//定义一个算术类型,其实就是int
14type Arith int
15
16//实现乘法的方法绑定到Arith类型,先不管为什么是这样的形式
17func (t *Arith) Multiply(args *Args, reply *int) error {
18    *reply = args.A * args.B
19    return nil
20}
21
22func main() {
23    //得到一个Arith类型的指针实例
24    arith := new(Arith)
25    //注册到rpc服务
26    rpc.Register(arith)
27    //挂到http服务上
28    rpc.HandleHTTP()
29    //开始监听
30    l, _ := net.Listen("tcp", ":1234")
31    http.Serve(l, nil)
32}

  rpc客户端

 1package main
2
3import (
4    "net/rpc"
5    "fmt"
6)
7
8type Args struct {
9    A, B int
10}
11
12func main() {
13    //连接服务器端,创建一个client
14    client, _ := rpc.DialHTTP("tcp", "127.0.0.1:1234")
15    args := &Args{7, 8}
16    var reply int
17    //通过Call方法调用Arith类型的Multiply方法,注意形参
18    client.Call("Arith.Multiply", args, &reply)
19    //得到调用结果,输出Arith: 7*8=56
20    fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)
21}

  上面2段程序很简短,可能你现在还不能理解其中的细节,但也请耐心看完,这个时候你应该能够心里有个rpc调用的概念了,客户端直接调用了服务器端的一个函数传递过去参数列表和接收返回值的对象,获得调用结果。

三、rpc的一些细节

  下面我们再来看一些rpc相关的细节

  首先能够被rpc调用的方法应该看起来像这样:

func (t *T) MethodName(argType T1, replyType *T2) error

  大概解释一下:

  • 函数必须是可导出的(首字母大写)
  • 必须有两个导出类型的参数,第一个参数用来接收参数,第二个参数是返回给客户端的结果参数,第二个参数必须是指针类型的
  • 函数还要有一个返回值error
  • T1、T2能够被encoding/gob编码

  看到这里你应该对于rpc的作用有了一定的认识,go中rpc包的用法简单来看就是准备一个类型,绑定一堆符合规范的方法,然后注册给rpc服务,监听客户端连接,客户端通过rpc包提供的Call方法可以调用到server注册好的方法。更多细节可以看一下官方文档:https://golang.org/pkg/net/rpc/

golang - gob与rpc的更多相关文章

  1. [转]Golang Gob编码

    Golang Gob编码 2012-08-24 09:47 by 轩脉刃, 5119 阅读, 1 评论, 收藏, 编辑 gob是Golang包自带的一个数据结构序列化的编码/解码工具.编码使用Enco ...

  2. golang中的RPC开发-2

    RPC简介 远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程 如果 ...

  3. golang中的rpc开发

    golang中实现RPC非常简单,官方提供了封装好的库,还有一些第三方的库 golang官方的net/rpc库使用encoding/gob进行编解码,支持tcp和http数据传输方式,由于其他语言不支 ...

  4. golang中的rpc包用法

    RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. 我所在公司的项目是采用基于Restful的微服务架构,随着微服 ...

  5. golang gob 有什么优势? gob/protobuf/json/xml 效率对比,benchmark 压力测试

    TODO 待研究: https://blog.csdn.net/love_se/article/details/7941876 https://blog.csdn.net/wangshubo1989/ ...

  6. golang学习之rpc实例

    rpc(远程过程调用),可以像调用本地程序一样调用远端服务,rpc分为http方式和tcp连接方式,使用http的rpc调用如下: 首先是server端: // rpc_server project ...

  7. protobuf、LRU、sigleflight

    今天咱一次讲3个吧,赶一下进度,好早点开始聊kubernetes! 从groupcache的项目目录结构看,我们今天要学习groupcachepb.lru.singleflight这3个package ...

  8. Golang入门教程(十六)Goridge -高性能的 PHP-to-Golang RPC编解码器库

    什么是 RPC 框架? RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在 ...

  9. Golang基础(7):go的net/rpc用法

    一:PRC是什么? RPC(Remote Procedure Call) 远程过程调用,是一个计算通信协议.该协议允许一台计算机上的程序调用另外一台计算机上的程序.远程过程调用就是2个不在同一台计算机 ...

随机推荐

  1. 阿森纳vs托特纳姆热刺

    阿森纳vs托特纳姆热刺之间进行的英格兰足球联盟杯比赛时间为2018年12月20日 03:45.本场比赛的亚盘初盘为阿森纳0.0,大小球初盘3.0,角球盘口10.5.在此之前,阿森纳和托特纳姆热刺两队进 ...

  2. 按模板批量修改Excel文件内容

    Sub 按模板修改Excel文件() Dim MoBanWorkBook As Workbook Set MoBanWorkBook = Application.ActiveWorkbook Dim ...

  3. thinkphp5使用空模块

    今天想做一个功能,可以后台设置url是二级域名(也是指向同一个服务器)还是一级域名(域名/模块),网上找了找,TP3.2开始取消了空模块.所以只能自己修改框架源码了. ----------有点晚,明天 ...

  4. 小程序----选择地理位置 ( wx.chooseLocation ) 和 获取地理位置 (wx.getSetting)

    问题来了:假如我第一次使用wx.chooseLocation()获取权限被拒绝,然后使用wx.getSetting()来重新获取权限该怎么做呢? 思路:wx.chooseLocation()有fail ...

  5. React state和props使用场景

    一个组件的显示状态可以由内部状态state.外部参数props所决定. props: 1.props 是从外部传进组件的参数,主要是父组件向子组件传递数据. 2.props 对于使用它的组件来说是只读 ...

  6. 已知一个字符串S 以及长度为n的字符数组a,编写一个函数,统计a中每个字符在字符串中的出现次数

    import java.util.Scanner; /** * @author:(LiberHome) * @date:Created in 2019/3/6 21:04 * @description ...

  7. OpenCV读写摄像头并写入视频

    #include <opencv2/opencv.hpp>using namespace cv;#include <iostream>using namespace std; ...

  8. Oracle 查询表空间使用情况

    select *   from (Select a.tablespace_name,                to_char(a.bytes / 1024 / 1024, '99,999.999 ...

  9. 认识Python和基础知识

    一.第一个Python程序 用vim编写,格式: vim hello.py 然后按 i 进入插入模式开始写代码,注意所有的代码都要用英文输入法,先写括号和引号,再在引号里面写内容(为了避免引号.括号不 ...

  10. 【RL-TCPnet网络教程】第3章 初学RL-TCPnet的准备工作及其快速上手

    第3章       初学RL-TCPnet的准备工作及其快速上手 俗话说万事开头难,学习一门新的知识,难的往往不是知识本身,而是如何快速上手,需要什么资料和开发环境.一旦上手后,深入的学习就相对容易些 ...