golang对prc进行了支持,使用时只需要导入net/rpc的包即可:
import "net/rpc"
rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。
只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:
- 方法是导出的
- 方法有两个参数,都是导出类型或内建类型
- 方法的第二个参数是指针
- 方法只有一个error接口类型的返回值
事实上,方法必须看起来像这样:
func (t *T) MethodName(argType T1, replyType *T2) error
其中T、T1和T2都能被encoding/gob包序列化。这些限制即使使用不同的编解码器也适用。(未来,对定制的编解码器可能会使用较宽松一点的限制)
方法的第一个参数代表 调用者提供的参数 ;第二个参数代表 返回给调用者的参数 。方法的返回值,如果非nil,将被作为字符串回传,在客户端看来就和errors.New创建的一样。如果返回了错误,回复的参数将不会被发送给客户端。
服务端可能会单个连接上调用ServeConn管理请求。更典型地,它会创建一个网络监听器然后调用Accept;或者,对于HTTP监听器,调用HandleHTTP和http.Serve。
想要使用服务的客户端会创建一个连接,然后用该连接调用NewClient。
更方便的函数Dial(DialHTTP)会在一个原始的连接(或HTTP连接)上依次执行这两个步骤。
生成的Client类型值有两个方法,Call和Go,它们的参数为要调用的服务和方法、一个包含参数的指针、一个用于接收接个的指针。
Call方法会等待远端调用完成,而Go方法异步的发送调用请求并使用返回的Call结构体类型的Done通道字段传递完成信号。
除非设置了显式的编解码器,本包默认使用encoding/gob包来传输数据。
执行以下前提:安装配置好golang开发环境
1.服务端
1.编辑服务端代码
mkdir -p $GOPATH/src/rpctest/ && cd $_ && go mod init rpctest && mkdir -p srv && cd $_ && vim main.go
内容如下:
package main
import (
"log"
"net"
"net/http"
"net/rpc"
)
type Rpc struct {
}
/*
- 方法是导出的
- 方法有两个参数,都是导出类型或内建类型
- 方法的第二个参数是指针
- 方法只有一个error接口类型的返回值
func (t *T) MethodName(argType T1, replyType *T2) error
*/
func (r *Rpc) GetSum(argType int, replyType *int) error {
*replyType = argType + 100
return nil
}
func main() {
// 1.结构体实例化
rp := new(Rpc)
// 2.rpc注册
rpc.Register(rp)
// 3.rpc网络
rpc.HandleHTTP()
// 4.监听网络
ln, err := net.Listen("tcp", "127.0.0.1:8899")
if err != nil {
log.Fatal(err)
}
// 5.等待网络连接
http.Serve(ln, nil)
}
2.开启服务端
cd $GOPATH/src/rpctest/srv && go run main.go
2.客户端
1.编辑客户端代码
再开一个终端执行客户端的操作,不要关闭服务端
mkdir -p $GOPATH/src/rpctest/ && cd $_ && mkdir -p cli && cd $_ && vim main.go
内容如下:
package main
import (
"log"
"net/rpc"
)
func main() {
// 1.连接服务器
cli, err := rpc.DialHTTP("tcp", "127.0.0.1:8899")
if err != nil {
log.Fatal(err)
}
// 2.调用函数
// serviceMethod :服务方法名,是一个 [ 结构体.方法名 ] 的字符串
// args :需要传入的参数
// reply : 接收的变量参数
//func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
var reply int
err = cli.Call("Rpc.GetSum", 99, &reply)
if err != nil {
log.Fatal(err)
}
// 3.打印结果
log.Println(reply)
}
2.执行客户端
前提:保证服务端已经开启
cd $GOPATH/src/rpctest/cli && go run main.go