首页 Golang教程Go 使用标准库 net/rpc 包

Go 使用标准库 net/rpc 包

运维派隶属马哥教育旗下专业运维社区,是国内成立最早的IT运维技术社区,欢迎关注公众号:yunweipai
领取学习更多免费Linux云计算、Python、Docker、K8s教程关注公众号:马哥linux运维

01 RPC 是什么?

RPC 是远程过程调用(Remote Procedure Call),用于调用方和被调用方两个进程间的交互,并且提供类似本地方法调用的形式。RPC 广泛用于在分布式系统中不同节点间的通信。

02 Go 语言 RPC 标准库

在 Go 语言的标准库中,也提供了一个简单的 RPC 实现(net/rpc)。rpc 包提供对对象在网络或其他 I/O 连接中导出方法的访问。服务器端注册对象,使其作为可见服务,服务的名称是对象类型名称。注册后,对象的导出方法将可远程访问。服务器可以注册不同类型的多个对象(服务),但注册同一类型的多个对象是错误的。

对象的导出方法有以下几点要求:

  • 方法的类型是可导出的。
  • 方法是可导出的。
  • 方法有两个参数,都是可导出类型或内置类型。
  • 方法的第二个参数是指针。
  • 方法返回一个错误类型。

实际上,方法看起来像这样:


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

其中 T1 和 T2 可以通过 encoding/gob 编码进行序列化。即使使用不同的编码解码器,这些限制也适用。将来,对自定义的编码解码器的限制可能会宽松一些。

该方法的第一个参数表示调用方提供的参数;第二个参数表示要返回给调用方的结果参数。方法的返回值(如果不是 nil)作为字符串传递回来,客户端认为该字符串就像由 errors.New 创建的错误一样。如果返回错误,则不会将回复参数发送回客户端。

服务器端可以调用 ServeConn 处理单个连接上的请求。更典型的是,它将创建一个网络监听器并调用 Accept,或者,对于 HTTP 监听器,调用 HandleHTTP 和 http.Serve。

想要使用该服务的客户端会建立连接,然后在连接上调用 NewClient。

更方便的函数是 Dial (DialHTTP) ,会在原始网络连接(HTTP 连接)依次执行这两个步骤。生成的 Client 对象有两个方法,即 Call 和 Go,它们的参数是要调用的服务和方法,一个包含参数的指针,一个用于接收结果的指针。

Call 方法等待远程调用完成。Go 方法异步发送调用请求,并使用返回的 Call结构体类型的 “Done 通道” 传递完成的信号。

除非显式设置了编码解码器,否则 net/rpc 包默认采用 encoding/gob 包编码解码数据。

03 RPC 怎么使用?

通过一个简单的示例,我们演示 Go 语言标准库 net/rpc 的使用方法。

RPC 方法:

服务器端定义一个可导出的 User 类型和一个符合 RPC 方法定义要求的 GetUser 方法:


type User struct {
  ID   int
  Name string
}
// rpc 方法
func (u *User) GetUser(id int, user *User) error {
  userMap := map[int]User{
    1: {ID: 1, Name: "frank"},
    2: {ID: 2, Name: "lucy"},
  }
  if userInfo, ok := userMap[id]; ok {
    *user = userInfo
  }
  return nil
}

服务器端:

服务器端被调用(用于 HTTP 服务):


func main() {
  _ = rpc.Register(new(message.User))
  rpc.HandleHTTP()
  listener, _ := net.Listen("tcp", ":8081")
  _ = http.Serve(listener, nil)
}

客户端:

此时,客户端可以看到具有 “User.GetUser” 方法的服务 “User”。要调用方法,客户端首先呼叫服务器端:


client, _ := rpc.DialHTTP("tcp", ":8081")

然后客户端可以进行远程调用:

Call 方法,同步调用:


id := 1
var user message.User
_ = client.Call("User.GetUser", id, &user)
fmt.Println(user)

Go 方法,异步调用:

userCall := client.Go("User.GetUser", id, &user, nil)
if replyCall := <-userCall.Done; replyCall != nil {
  fmt.Println(user)
}

服务器端的实现通常为客户端提供简单、类型安全的包装。

net/rpc 包已冻结,不接受新功能。

04 总结

本文简要描述 Go 语言标准库 net/rpc 包的使用方法,通过阅读本文,读者应该已经对Go 语言标准库 net/rpc 有了初步的认识。

原文:https://mp.weixin.qq.com/s/IospmGnkC-y9ddJx_9JGzg

本文链接:https://www.yunweipai.com/41539.html

网友评论comments

发表回复

您的电子邮箱地址不会被公开。

暂无评论

Copyright © 2012-2022 YUNWEIPAI.COM - 运维派 京ICP备16064699号-6
扫二维码
扫二维码
返回顶部