import "net/rpc"
rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。
服务端
package main
import (
"errors"
"net"
"net/rpc"
"log"
"net/http"
)
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
// 这个类型即将用于注册rpc服务
type Arith int
// 定义乘法服务
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
// 定义除法服务
func (t *Arith) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
arith := new(Arith) // 新建一个对象
rpc.Register(arith) // 服务端注册一个对象 相同类型的对象只能注册一个
rpc.HandleHTTP() // 注册默认的http处理函数
l, e := net.Listen("tcp", ":1234") // 网络监听tcp
if e != nil {
log.Fatal("listen error:", e)
}
http.Serve(l, nil) // 启动http服务器 一般会调用 go http.Serve(l,nil)另开启线程
}
客户端
package main
import (
"net/rpc"
"log"
"fmt"
)
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
func main() {
client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234") // DialHTTP在指定的网络和地址与在默认HTTP RPC路径监听的HTTP RPC服务端连接。
if err != nil {
log.Fatal("dialing:", err)
}
// Synchronous call
args := &Args{7,8} // 新建一个参数
var reply int // 保存rpc返回值
err = client.Call("Arith.Multiply", args, &reply) // Call调用指定的方法,等待调用返回,将结果写入reply,然后返回执行的错误状态。
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)
// Asynchronous call
quotient := new(Quotient) // 新建一个变量
divCall := client.Go("Arith.Divide", args, quotient, nil) // Go异步的调用函数 最后参数为nil,表示开启一个线程去执行,也可以指定一个有缓存的通道
replyCall := <-divCall.Done // will be equal to divCall 获取返回值
if replyCall.Error != nil {
log.Fatal("arith error:", replyCall.Error)
}
fmt.Printf("Arith: %d/%d=%d...%d", args.A, args.B, quotient.Quo, quotient.Rem)
// check errors, print, etc.
}
网友评论