在使用 Golang 的 net/rpc 包进行 RPC 服务开发时,我们有时候会遇到需要获取客户端的真实 IP 和当前连接 net.Conn 的需求。然而在 net/rpc 的服务处理方法中,并没有提供直接获取到这些信息的途径。
那么,我们应该如何去获取这些信息呢?实现这个功能会有一些复杂,因为RPC的默认处理器没有提供获取net.Conn连接对象的接口。我们需要自定义RPC的编解码器和处理器来获得这些信息。以下是我的解决方案:
首先,我们要创建一个新的RPC服务处理器:
type serverCodec struct { rwc io.ReadWriteCloser dec *gob.Decoder // for reading JSON values enc *gob.Encoder // for writing JSON values encBuf *bufio.Writer conn net.Conn } func (c *serverCodec) ReadRequestHeader(r *rpc.Request) error { err := c.dec.Decode(r) if err != nil { return err } return nil } func (c *serverCodec) ReadRequestBody(body interface{}) error { return c.dec.Decode(body) } func (c *serverCodec) WriteResponse(resp *rpc.Response, body interface{}) error { err := c.enc.Encode(resp) if err != nil { return err } err = c.enc.Encode(body) if err != nil { return err } return c.encBuf.Flush() } func (c *serverCodec) Close() error { c.encBuf.Flush() return c.rwc.Close() } func NewServerCodec(conn net.Conn) rpc.ServerCodec { buf := bufio.NewWriter(conn) return &serverCodec{ rwc: conn, dec: gob.NewDecoder(conn), enc: gob.NewEncoder(buf), encBuf: buf, conn: conn, } }
上面的代码创建了一个符合rpc.ServerCodec接口的新的编解码器。该编解码器在处理请求和响应时会获取到当前的net.Conn连接。
然后我们需要自定义我们的RPC服务,使其在处理请求时能够使用自定义的编解码器。
func main() { // Create an instance of the MathService mathService := new(MathService) // Register MathService for RPC rpc.Register(mathService) // Create a TCP listener listener, err := net.Listen("tcp", "0.0.0.0:1234") if err != nil { fmt.Println("Error starting server:", err) return } defer listener.Close() fmt.Println("Server listening on :1234") for { // Accept incoming connections conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting connection:", err) continue } // Use our custom codec to Serve the connection in a new goroutine go rpc.ServeCodec(NewServerCodec(conn)) } }
这样,我们的RPC服务就会使用自定义的编解码器来处理每一个请求,每一个连接对应一个编解码器,我们可以从编解码器中获取到连接信息。
需要注意的是,在我们的服务方法中,我们依然不能直接获得该连接信息,我们需要在方法被调用之前或之后去获取。具体的实现方式可能需要你再进行一些代码的修改和调整。但是希望以上的内容能够帮助你解决这个问题。