go rpc示例

雪域迷影 · · 385 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

最近在Youtube上面看到一个关于:golang rpc包的示例视频:youtube视频地址:Building a Basic RPC Server and Client with Go,其相应源代码的Github仓库地址为:https://github.com/tensor-programming/go-basic-rpc,需要的话可以自行获取:

git clone https://github.com/tensor-programming/go-basic-rpc.git

golang rpc包

关于golang中的rpc库,可以查看官方文档:https://golang.org/pkg/net/rpc/https://pkg.go.dev/net/rpc,如下图所示:

golang rpc

简单的示例(不使用rpc)

下面对一个带有Title和Body的Item数组对象database,编写增删改查的方法,并进行简单的测试,相应的Go代码示例如下:

package main

import (
    "fmt"
)

type Item struct {
    Title string
    Body  string
}

var database []Item

// 根据title名称从database数组中获取对应的Item对象
func GetByName(title string) Item {
    var getItem Item

    for _, val := range database {
        if val.Title == title {
            getItem = val
        }
    }

    return getItem
}

// 添加一个新的Item对象
func AddItem(item Item) Item {
    database = append(database, item)
    return item
}

// 根据title在database中查询对应的Item对象,如果存在则进行更新
func EditItem(title string, edit Item) Item {
    var changed Item

    for idx, val := range database {
        if val.Title == title {
            database[idx] = edit
            changed = edit
        }
    }

    return changed
}

// 删除某个item对象
func DeleteItem(item Item) Item {
    var del Item

    for idx, val := range database {
        if val.Title == item.Title && val.Body == item.Body {
            database = append(database[:idx], database[idx+1:]...)
            del = val
            break
        }
    }

    return del
}

func main() {
    fmt.Println("initial database: ", database)
    a := Item{"first", "a test item"}
    b := Item{"second", "a second item"}
    c := Item{"third", "a third item"}

    AddItem(a)
    AddItem(b)
    AddItem(c)

    fmt.Println("second database: ", database)

    DeleteItem(b)
    fmt.Println("third database: ", database)

    EditItem("third", Item{"fourth", "a new item"})
    fmt.Println("fourth database: ", database)

    x := GetByName("fourth")
    y := GetByName("first")
    fmt.Println(x, y)
}

执行命令go run main,go得出如下的输出:

test main.go

go_basic_rpc示例(包括rpc服务端和rpc客户端)

首先创建一个go-basic-rpc的目录,在其下创建一个server.go用于编写go rpc服务端,再创建一个client目录,然后在client目录下创建一个client.go文件用于编写go rpc客户端。最终的目录结构如下所示:

go_basic_rpc的目录结构

go rpc服务端server.go代码如下:

package main

import (
    "log"
    "net"
    "net/http"
    "net/rpc"
)

type Item struct {
    Title string
    Body  string
}

type API int

var database []Item

func (a *API) GetDB(empty string, reply *[]Item) error {
    *reply = database
    return nil
}

func (a *API) GetByName(title string, reply *Item) error {
    var getItem Item

    for _, val := range database {
        if val.Title == title {
            getItem = val
        }
    }

    *reply = getItem

    return nil
}

func (a *API) AddItem(item Item, reply *Item) error {
    database = append(database, item)
    *reply = item
    return nil
}

func (a *API) EditItem(item Item, reply *Item) error {
    var changed Item

    for idx, val := range database {
        if val.Title == item.Title {
            database[idx] = Item{item.Title, item.Body}
            changed = database[idx]
        }
    }

    *reply = changed
    return nil
}

func (a *API) DeleteItem(item Item, reply *Item) error {
    var del Item

    for idx, val := range database {
        if val.Title == item.Title && val.Body == item.Body {
            database = append(database[:idx], database[idx+1:]...)
            del = item
            break
        }
    }

    *reply = del
    return nil
}

func main() {
    api := new(API)
    err := rpc.Register(api)
    if err != nil {
        log.Fatal("error registering API", err)
    }

    rpc.HandleHTTP()

    listener, err := net.Listen("tcp", ":4040")

    if err != nil {
        log.Fatal("Listener error", err)
    }
    log.Printf("serving rpc on port %d", 4040)
    http.Serve(listener, nil)

    if err != nil {
        log.Fatal("error serving: ", err)
    }

    // fmt.Println("initial database: ", database)
    // a := Item{"first", "a test item"}
    // b := Item{"second", "a second item"}
    // c := Item{"third", "a third item"}

    // AddItem(a)
    // AddItem(b)
    // AddItem(c)
    // fmt.Println("second database: ", database)

    // DeleteItem(b)
    // fmt.Println("third database: ", database)

    // EditItem("third", Item{"fourth", "a new item"})
    // fmt.Println("fourth database: ", database)

    // x := GetByName("fourth")
    // y := GetByName("first")
    // fmt.Println(x, y)

}

go rpc客户端client/client.go代码如下:

package main

import (
    "fmt"
    "log"
    "net/rpc"
)

type Item struct {
    Title string
    Body  string
}

func main() {
    var reply Item
    var db []Item

    client, err := rpc.DialHTTP("tcp", "localhost:4040")

    if err != nil {
        log.Fatal("Connection error: ", err)
    }

    a := Item{"First", "A first item"}
    b := Item{"Second", "A second item"}
    c := Item{"Third", "A third item"}

    client.Call("API.AddItem", a, &reply)
    client.Call("API.AddItem", b, &reply)
    client.Call("API.AddItem", c, &reply)
    client.Call("API.GetDB", "", &db)

    fmt.Println("Database: ", db)

    client.Call("API.EditItem", Item{"Second", "A new second item"}, &reply)

    client.Call("API.DeleteItem", c, &reply)
    client.Call("API.GetDB", "", &db)
    fmt.Println("Database: ", db)

    client.Call("API.GetByName", "First", &reply)
    fmt.Println("first item: ", reply)

}

运行rpc服务端和客户端

  • 运行rpc服务端
cd /root/Programming/GoPro/go-basic-rpc
go run server.go
  • 运行rpc客户端
cd /root/Programming/GoPro/go-basic-rpc/client
go run client.go
运行go_basic_rpc服务端和客户端

参考资料


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:雪域迷影

查看原文:go rpc示例

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

385 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传