go rpc示例

2020-11-26 11:49:20 浏览数 (1)

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

代码语言:javascript复制
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,如下图所示:

简单的示例(不使用rpc)

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

代码语言:javascript复制
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得出如下的输出:

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

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

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

代码语言:javascript复制
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代码如下:

代码语言:javascript复制
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服务端
代码语言:javascript复制
cd /root/Programming/GoPro/go-basic-rpc
go run server.go
  • 运行rpc客户端
代码语言:javascript复制
cd /root/Programming/GoPro/go-basic-rpc/client
go run client.go

参考资料

  • youtube视频地址:Building a Basic RPC Server and Client with Go
  • Github代码:https://github.com/tensor-programming/go-basic-rpc
  • https://github.com/grpc/grpc-go
  • https://golang.org/pkg/net/rpc/
  • https://pkg.go.dev/net/rpc

0 人点赞