在RPC调用中确定请求者的IP地址

In Go using the standard net/rpc functionality, I would like to determine what the IP address an inbound RPC request is coming from. The underlying http functionality appears to provide this in the http.Request object, but I cannot see any way of getting at that from the default RPC handler (set using rpc.HandleHTTP).

Is there some hidden mechanism for getting at the underlying http.Request, or do I have to do something fancier with setting up a different HTTP responder?

You can also use https://github.com/valyala/gorpc instead of net/rpc, which passes client address to RPC server handler - see http://godoc.org/github.com/valyala/gorpc#HandlerFunc for details.

The net/rpc package is at a higher level of abstraction than tcp or http. Since it can use multiple codecs it doesn't make sense for it to offer a way to get at the ip address of the inbound rpc. It's theoretically possible someone could implement a code that talks on unix sockets instead or using radio transmitters.

If you want access to specifics of the transport layer you will have to drop a level in the stack and use net or net/http directory to make your rpc service.

As far as I know, it is not possible to grab the address from somewhere in the default server.

The service call method, which calls the request receiving function, does not provide any access to the remote data stored in the codec.

If http handlers could be registered twice (which they can't), you could have overwritten the DefaultRPCPath for the HTTP Handler setup by HandleHTTP. But that's simply not possible today.

What you can do, without much fuss, is to build a RPC server based on the default one with your own ServeHTTP method:

import (
    "log"
    "net"
    "net/http"
    "net/rpc"
)

type myRPCServer struct {
   *rpc.Server
}

func (r *myRPCServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   log.Println(req.RemoteAddr)
   r.Server.ServeHTTP(w, req)
}

func (r *myRPCServer) HandleHTTP(rpcPath, debugPath string) {
    http.Handle(rpcPath, r)
}

func main() {
    srv := &myRPCServer{rpc.NewServer()}
    srv.HandleHTTP(rpc.DefaultRPCPath, rpc.DefaultDebugPath)

    // ...http listen code...
}

The downside of this, is of course, that you can't use rpc.Register anymore. You have to write srv.Register.

Edit: I forgot that you'd need to write your own HandleHTTP as well. The reason for this is, that if you embed the RPC server and you write srv.HandleHTTP it is called on the embedded instance, passing the embedded instance to http.Handle(), ignoring your own definition of ServeHTTP. This has the drawback, that you won't have the ability to debug your RPC server using the debug path, as the server's HandleHTTP uses a private debug handler (rpc.debugHTTP) which you can't access.

It seems that there is currently no way to do this in rpc function. See this link for more info

Here is a summary.

Q:

Right now RemoteAddr() method can be called to get the RPC client's address only on net.Conn when the client dials to server, but suppose that your server has multiple clients connected and each of this clients are calling an RPC exported method. Is there a way to implement a method to get the caller's remote address from inside the RPC method?

func (t *Type) Method(args *Args, reply *string) error {
//something like
*reply = Caller.RemoteAddr().String()
// who called the method now?
return nil
}

A:

I'm skeptical. It would take an API change (not necessarily a backwards incompatible one but still a bit of a redesign) to supply this.