https://pkg.go.dev/net/rpc
    OverView
    Package rpc provides access to the exported methods of an object across a network or other I/O connection.
    提供exported access via a network / IO connection

    A server registers an object, making it visible as a service with the name of the type of the object. After registration, exported methods of the object will be accessible remotely. A server may register multiple objects (services) of different types but it is an error to register multiple objects of the same type.

    Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored:
    只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:

    1. - the method's type is exported.
    2. //方法类型是导出的
    3. - the method is exported.
    4. //方法是导出的
    5. - the method has two arguments, both exported (or builtin) types.
    6. //方法有两个参数,都是导出的或者内建的
    7. - the method's second argument is a pointer.
    8. //方法的第二参数是指针
    9. - the method has return type error.
    10. //方法只有一个error接口类型的返回值

    In effect, the method must look schematically like

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

    where T1 and T2 can be marshaled(序列化) by encoding/gob. These requirements apply even if a different codec(编解码器) is used. (In the future, these requirements may soften for custom codecs.)

    The method’s first argument represents the arguments provided by the caller;
    方法的第一参数代表调用者提供的参数
    the second argument represents the result parameters to be returned to the caller.
    第二个参数代表
    The method’s return value, if non-nil, is passed back as a string that the client sees as if created by errors.New. If an error is returned, the reply parameter will not be sent back to the client.

    The server may handle requests on a single connection by calling ServeConn. More typically it will create a network listener and call Accept or, for an HTTP listener, HandleHTTP and http.Serve.

    A client wishing to use the service establishes a connection and then invokes NewClient on the connection. The convenience function Dial (DialHTTP) performs both steps for a raw network connection (an HTTP connection). The resulting Client object has two methods, Call and Go, that specify the service and method to call, a pointer containing the arguments, and a pointer to receive the result parameters.

    The Call method waits for the remote call to complete while the Go method launches the call asynchronously and signals completion using the Call structure’s Done channel.
    Call 方法会等待远程调用完成, Go方法异步的发送调用请求并使用返回的call结构体的Done channel

    Here is a simple example. A server wishes to export an object of type Arith:
    一个服务器想要到处Arith类型的一个对象

    package server
    
    import "errors"
    
    type Args struct {
        A, B int
    }
    
    type Quotient struct {
        Quo, Rem int
    }
    
    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
    }
    

    The server calls (for HTTP service): 服务端会调用:

    arith := new(Arith)
    rpc.Register(arith)
    rpc.HandleHTTP()
    l, e := net.Listen("tcp", ":1234")
    if e != nil {
        log.Fatal("listen error:", e)
    }
    go http.Serve(l, nil)
    

    At this point, clients can see a service “Arith” with methods “Arith.Multiply” and “Arith.Divide”. To invoke one, a client first dials the server:
    此时,客户端可以看到服务”Arith”和其他方法, 要调用方法, 客户端要呼叫服务器

    client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
    if err != nil {
        log.Fatal("dialing:", err)
    }
    

    Then it can make a remote call:

    // Synchronous call
    args := &server.Args{7,8}
    var reply int
    err = client.Call("Arith.Multiply", args, &reply)
    if err != nil {
        log.Fatal("arith error:", err)
    }
    fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
    

    or

    // Asynchronous call
    quotient := new(Quotient)
    divCall := client.Go("Arith.Divide", args, quotient, nil)
    replyCall := <-divCall.Done    // will be equal to divCall
    // check errors, print, etc.