文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Golang远程调用框架RPC的具体使用

2022-12-14 12:00

关注

gRPC

gRPC远程过程调用框架是基于动作的模式,类似远程调用微服务。这使得gRPC成为一种围绕Protobufs构建的进程间通信(IPC)协议,用于处理客户端和服务器之间的消息传递。gRPC非常适合密集而高效的通信,因为它支持客户端和服务器流。

与REST对比

REST是一种基于资源的协议,客户端根据请求体告诉服务器需要创建、读取、更新或删除哪些资源。gRPC还可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。gRPC为什么比REST更快?

gRPC利用HTTP/2协议,提供多种方式提供性能:

需求说明

Go RPC服务器允许注册任何Go类型及其方法,通过RPC协议公开这些方法,即可以从远程客户端按名称进行调用。我们要实现的需求可以简单描述为:

当然我们还可以实现其他更复杂的功能,这里为了简化,仅说明这几个方法。下面首先定义Book类型:

// Book represents a book entry
type Book struct {
ISBN string
Title, Author string
Year, Pages int
}
// ReadingList keeps tracks of books and pages read
type ReadingList struct {
Books []Book
Progress []int
}

ReadingList 类内部包括两个slice,模拟数据库存储书籍及对应进度。下面定义助手方法:

func (r *ReadingList) bookIndex(isbn string) int {
	for i := range r.Books {
		if isbn == r.Books[i].ISBN {
			return i
		}
	}
	return -1
}

上面通过ISBN查询书籍对应索引号,现在继续在ReadingList类型上定义几个方法:

// AddBook checks if the book is not present and adds it
func (r *ReadingList) AddBook(b Book) error {
	if b.ISBN == "" {
		return ErrISBN
	}
	if r.bookIndex(b.ISBN) != -1 {
		return ErrDuplicate
	}
	r.Books = append(r.Books, b)
	r.Progress = append(r.Progress, 0)
	return nil
}
// GetProgress returns the progress of a book
func (r *ReadingList) GetProgress(isbn string) (int, error) {
	if isbn == "" {
		return -1, ErrISBN
	}
	i := r.bookIndex(isbn)
	if i == -1 {
		return -1, ErrMissing
	}
	return r.Progress[i], nil
}
// 设置进度
func (r *ReadingList) SetProgress(isbn string, pages int) error {
	if isbn == "" {
		return ErrISBN
	}
	i := r.bookIndex(isbn)
	if i == -1 {
		return ErrMissing
	}
	if p := r.Books[i].Pages; pages > p {
		pages = p
	}
	r.Progress[i] = pages
	return nil
}

我们需求就是通过RPC协议公开这些方法,让客户端进行远程调用。下面实现RPC服务器。

创建RPC服务器

上节已经准备好了公开的方法,创建RPC服务需要遵守一些规则:

语法如下:

 func (t *T) Method(in T1, out *T2) error

知道了方法规范,下面对上节的方法进行包装,首先我们定义几个错误类型:

// List of errors
var (
    ErrISBN = fmt.Errorf("missing ISBN")
    ErrDuplicate = fmt.Errorf("duplicate book")
    ErrMissing = fmt.Errorf("missing book")
)

再定义一个助手方法:

// sets the success pointer value from error
func setSuccess(err error, b *bool) error {
	*b = err == nil
	return err
}

首先实现Addbook和GetProgress包装方法:

func (r *ReadingService) AddBook(b Book, success *bool) error {
	return setSuccess(r.ReadingList.AddBook(b), success)
}
func (r *ReadingService) GetProgress(isbn string, pages *int) (err error) {
	*pages, err = r.ReadingList.GetProgress(isbn)
	return err
}

由于更新阅读进度需要传入两个参数,但rpc方法不能传入多个参数,因此我们定义类型进行参数封装:

type Progress struct {
	ISBN  string
	Pages int
}
func (r *ReadingService) SetProgress(p Progress, success *bool) error {
	return setSuccess(r.ReadingList.SetProgress(p.ISBN, p.Pages), success)
}

准备了包装方法,下面定义RPC服务就很简单了:

func main() {
	if err := rpc.Register(&book.ReadingService{}); err != nil {
		log.Fatalln(err)
	}
	rpc.HandleHTTP()
	l, err := net.Listen("tcp", ":8900")
	if err != nil {
		log.Fatalln(err)
	}
	log.Println("Server Started")
	if err := http.Serve(l, nil); err != nil {
		log.Fatal(err)
	}
}

服务端实现完毕,下面实现客户端。基础类型Book,Progress再客户端也需要使用,因此可以独立定义进行共享。

// Book represents a book entry
type Book struct {
	ISBN          string
	Title, Author string
	Year, Pages   int
}
type Progress struct {
	ISBN  string
	Pages int
}

实现客户端

首先定义测试数据:

const hp = "H.P. Lovecraft"
var books = []Book{
	{ISBN: "1540335534", Author: hp, Title: "The Call of Cthulhu", Pages: 36},
	{ISBN: "1980722803", Author: hp, Title: "The Dunwich Horror ", Pages: 53},
	{ISBN: "197620299X", Author: hp, Title: "The Shadow Over Innsmouth", Pages: 40},
	{ISBN: "1540335536", Author: hp, Title: "The Case of Charles Dexter Ward", Pages: 176},
}

下面定义rpc客户端:

	client, err := rpc.DialHTTP("tcp", ":8900")
	if err != nil {
		log.Fatalln(err)
	}
	defer client.Close()

连接服务端后,可以调用服务端方法,下面定义统一方法进行调用:

func callClient(client *rpc.Client, method string, in, out interface{}) {
	var r interface{}
	if err := client.Call(method, in, out); err != nil {
		out = err
	}
	switch v := out.(type) {
	case error:
		r = v
	case *int:
		r = *v
	case *bool:
		r = *v
	}
	log.Printf("%s: [%+v] -> %+v", method, in, r)
}

最后是循环测试数据,依此调用RPC方法:

	for i, book := range books {
		callClient(client, "ReadingService.AddBook", book, new(bool))

		callClient(client, "ReadingService.SetProgress", Progress{
			ISBN:  book.ISBN,
			Pages: 10 + i*i,
		}, new(bool))

		callClient(client, "ReadingService.GetProgress", book.ISBN, new(int))
	}
}

完整代码如下:

package main
import (
	log "log"
	"net/rpc"
)
func main() {
	client, err := rpc.DialHTTP("tcp", ":8900")
	if err != nil {
		log.Fatalln(err)
	}
	defer client.Close()
	for i, book := range books {
		callClient(client, "ReadingService.AddBook", book, new(bool))
		callClient(client, "ReadingService.SetProgress", Progress{
			ISBN:  book.ISBN,
			Pages: 10 + i*i,
		}, new(bool))
		callClient(client, "ReadingService.GetProgress", book.ISBN, new(int))
	}
}
// Book represents a book entry
type Book struct {
	ISBN          string
	Title, Author string
	Year, Pages   int
}
type Progress struct {
	ISBN  string
	Pages int
}
const hp = "H.P. Lovecraft"
var books = []Book{
	{ISBN: "1540335534", Author: hp, Title: "The Call of Cthulhu", Pages: 36},
	{ISBN: "1980722803", Author: hp, Title: "The Dunwich Horror ", Pages: 53},
	{ISBN: "197620299X", Author: hp, Title: "The Shadow Over Innsmouth", Pages: 40},
	{ISBN: "1540335536", Author: hp, Title: "The Case of Charles Dexter Ward", Pages: 176},
}
func callClient(client *rpc.Client, method string, in, out interface{}) {
	var r interface{}
	if err := client.Call(method, in, out); err != nil {
		out = err
	}
	switch v := out.(type) {
	case error:
		r = v
	case *int:
		r = *v
	case *bool:
		r = *v
	}
	log.Printf("%s: [%+v] -> %+v", method, in, r)
}

到此这篇关于Golang远程调用框架RPC的具体使用的文章就介绍到这了,更多相关Go RPC内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯