英文:
Determining requester's IP address in RPC call
问题
在Go中使用标准的net/rpc
功能,我想确定一个传入的RPC请求来自哪个IP地址。底层的http
功能似乎在http.Request
对象中提供了这个功能,但是我无法从默认的RPC处理程序(使用rpc.HandleHTTP
设置)中获取到它。
是否有一些隐藏的机制可以获取底层的http.Request
,还是我需要通过设置一个不同的HTTP响应器来做一些更复杂的操作?
英文:
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?
答案1
得分: 4
据我所知,从默认服务器的某个地方获取地址是不可能的。
调用service call method的请求接收函数不提供访问存储在编解码器中的远程数据的任何途径。
如果http处理程序可以注册两次(它们不能),您可以覆盖由HandleHTTP
设置的HTTP处理程序的DefaultRPCPath
。但是,这在今天是不可能的。
您可以做的是,在默认RPC服务器的基础上构建一个自己的ServeHTTP
方法的RPC服务器:
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...
}
这样做的缺点是,您不能再使用rpc.Register
。您必须编写srv.Register
。
**编辑:**我忘记了您还需要编写自己的HandleHTTP
。原因是,如果您嵌入了RPC服务器并编写了srv.HandleHTTP
,它将在嵌入实例上调用,将嵌入实例传递给http.Handle()
,忽略您自己定义的ServeHTTP
。这有一个缺点,即您将无法使用调试路径调试RPC服务器,因为服务器的HandleHTTP
使用了一个私有调试处理程序(rpc.debugHTTP
),您无法访问。
英文:
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.
答案2
得分: 1
net/rpc
包比tcp或http更抽象化。由于它可以使用多个编解码器,因此它没有提供一种获取入站rpc的IP地址的方法是没有意义的。从理论上讲,有人可以实现一个使用Unix套接字或无线电发射器进行通信的代码。
如果您想要访问传输层的具体细节,您将需要在堆栈中降低一个级别,并使用net
或net/http
目录来创建您的rpc服务。
英文:
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.
答案3
得分: 1
你也可以使用https://github.com/valyala/gorpc来替代net/rpc,它会将客户端地址传递给RPC服务器处理程序-详见http://godoc.org/github.com/valyala/gorpc#HandlerFunc。
英文:
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.
答案4
得分: 0
看起来目前在rpc函数中没有办法做到这一点。更多信息请参见此链接。
以下是摘要。
问:
>现在只有在客户端拨号到服务器时,才能调用RemoteAddr()方法来获取RPC客户端的地址,但假设您的服务器有多个连接的客户端,并且每个客户端都在调用一个RPC导出方法。有没有办法在RPC方法内部实现一个方法来获取调用者的远程地址?
> func (t *Type) Method(args *Args, reply *string) error {
> //类似于
> *reply = Caller.RemoteAddr().String()
> //现在是谁调用了这个方法?
> return nil
> }
答:
>我持怀疑态度。这将需要一个API更改(不一定是向后不兼容的更改,但仍然需要进行一些重新设计)来提供这个功能。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论