golang——net/rpc包学习
1、rpc包
rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。
只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:
(1)方法是导出的
(2)方法有两个参数,都是导出类型或内建类型
(3)方法的第二个参数是指针
(4)方法只有一个error接口类型的返回值
func (t *T) MethodName(argType T1, replyType *T2) error
其中T、T1和T2都能被encoding/gob包序列化。
方法的第一个参数代表调用者提供的参数;第二个参数代表返回给调用者的参数。
方法的返回值,如果非nil,将被作为字符串回传,在客户端看来就和errors.New创建的一样。
如果返回了错误,回复的参数将不会被发送给客户端。
代码示例:
package main import ( "errors" "fmt" "log" "net" "net/http" "net/rpc" ) // Args 参数 type Args struct { A, B int } // Quotient 商、余数 type Quotient struct { Quo, Rem int } // Arith 算术服务 type Arith int // Multiply 乘法服务 func (*Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil } // Divide 除法服务 func (*Arith) Divide(args *Args, quo *Quotient) error { if args.B == 0 { return errors.New("除数不能为零") } quo.Quo = args.A / args.B quo.Rem = args.A % args.B return nil } // 错误检查 func checkErr(err error) { if err != nil { log.Fatalln(err) } } func main() { //开启服务 arith := new(Arith) //使用默认服务对象 err := rpc.Register(arith) checkErr(err) //默认路径 // const ( // DefaultRPCPath = "/_goRPC_" // DefaultDebugPath = "/debug/rpc" // ) rpc.HandleHTTP() //设置监听 lis, err := net.Listen("tcp", ":1234") checkErr(err) go http.Serve(lis, nil) //客户端请求服务 client, err := rpc.DialHTTP("tcp", ":1234") checkErr(err) defer client.Close() //乘法 args := &Args{A: 17, B: 3} var reply int err = client.Call("Arith.Multiply", args, &reply) checkErr(err) fmt.Printf("Arith.Multiply:%d * %d = %d\n", args.A, args.B, reply) //除法 quotient := new(Quotient) call := client.Go("Arith.Divide", args, quotient, nil) <-call.Done fmt.Printf("Arith.Divide:%d / %d = %d .... %d\n", args.A, args.B, quotient.Quo, quotient.Rem) } //输出 //Arith.Multiply:17 * 3 = 51 // Arith.Divide:17 / 3 = 5 .... 2
2、客户端
2.1、type Client struct{}
Client类型代表RPC客户端。
同一个客户端可能有多个未返回的调用,也可能被多个go程同时使用。
2.2、常用方法
(1)func NewClient(conn io.ReadWriteCloser) *Client
NewClient返回一个新的Client,以管理对连接另一端的服务的请求。
(2)func Dial(network, address string) (*Client, error)
Dial在指定的网络和地址与RPC服务端连接。
(3)func DialHTTP(network, address string) (*Client, error)
DialHTTP在指定的网络和地址与在默认HTTP RPC路径监听的HTTP RPC服务端连接。
(4)func DialHTTPPath(network, address, path string) (*Client, error)
DialHTTPPath在指定的网络、地址和路径与HTTP RPC服务端连接。
(5)func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
Call调用指定的方法,等待调用返回,将结果写入reply,然后返回执行的错误状态。
(6)func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call
Go异步的调用函数。本方法Call结构体类型指针的返回值代表该次远程调用。
通道类型的参数done会在本次调用完成时发出信号(通过返回本次Go方法的返回值)。
如果done为nil,Go会申请一个新的通道(写入返回值的Done字段);如果done非nil,done必须有缓冲,否则Go方法会故意崩溃。
(7)func (client *Client) Close() error
关闭客户端。
3、服务端
3.1、type Server struct{}
rpc包提供默认的服务对象,可直接通过“rpc.”进行使用。
3.2、常用方法
(1)func NewServer() *Server
创建并返回一个*Server。
(2)func (server *Server) Register(rcvr interface{}) error
注册服务。
如果rcvr不是一个导出类型的值,或者该类型没有满足要求的方法,Register会返回错误。
Register也会使用log包将错误写入日志。
客户端可以使用格式为"Type.Method"的字符串访问这些方法,其中Type是rcvr的具体类型。
(3)func (server *Server) RegisterName(name string, rcvr interface{}) error
RegisterName类似Register,但使用提供的name代替rcvr的具体类型名作为服务名。
(4)func (server *Server) Accept(lis net.Listener)
Accept接收监听器l获取的连接,然后服务每一个连接。
Accept会阻塞,调用者应另开线程。
(5)func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP实现了回应RPC请求的http.Handler接口。
(6)func (server *Server) HandleHTTP(rpcPath, debugPath string)
HandleHTTP注册server的RPC信息HTTP处理器对应到rpcPath,注册server的debug信息HTTP处理器对应到debugPath。
HandleHTTP会注册到http.DefaultServeMux。之后,仍需要调用http.Serve(),一般会另开线程:"go http.Serve(l, nil)"