我有一个需求,需要rpc服务器获取客户端的真实IP和当前连接
net.Conn
。
我以前是通过下面的示例方法获取的
// example_server.go
type MathService struct{}
type Args struct {
A, B int
}
type Reply struct {
Result int
}
func (m *MathService) Multiply(args *Args, reply *Reply) error {
reply.Result = args.A * args.B
return nil
}
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
}
fmt.Printf("remote ip addr: %s\n", conn.RemoteAddr().String())
// Serve the connection in a new goroutine
go rpc.ServeConn(conn)
}
}
// example_client.go
type Args struct {
A, B int
}
type Reply struct {
Result int
}
func main() {
// Connect to the server
client, err := rpc.Dial("tcp", "127.0.0.1:1234")
if err != nil {
fmt.Println("Error connecting to server:", err)
return
}
defer client.Close()
// Prepare the arguments for the RPC call
args := &Args{A: 5, B: 3}
// Call the Multiply method remotely
var reply Reply
err = client.Call("MathService.Multiply", args, &reply)
if err != nil {
fmt.Println("Error calling Multiply:", err)
return
}
// Print the result
fmt.Printf("Result: %d\n", reply.Result)
}
但是
RemoteAddr
方法获取到的不一定是客户端的真实IP。
因此,我希望手动调用
ReportRealIP
函数来报告真实IP,但是在rpc函数中无法获取到当前连接的
net.Conn
。
但是我查了一些资料,没有找到办法实现我的需求。有没有办法获得我想要的两个变量?期待您的回复
需要真实IP和
的原因大致是为了双向通信。我希望能够向特定IP的客户端发送RPC请求来执行某些操作。例如,向某些Agent服务发出RPC命令来执行某个脚本。net.Conn
其他信息
我预期结果的伪代码
// client.go
rpc.Call("Server.ReportRealIP","1,2,3,4", resp)
// server.go
var globalMap map[string]net.Conn
func (m *Server) ReportRealIP(args *string, reply *Reply) error {
clientRealIP := args
// get current call net.Conn
globalMap[clientRealIP] = current net.Conn
return nil
}
在Go的标准库中,rpc包并没有提供直接获取底层net.Conn或者客户端真实IP地址的方法。但是,您可以通过为 net.Conn 创建包装器并实现包含您需要的信息的自定义编解码器来实现您的目标
package main
import (
"fmt"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
type MathService struct{}
type Args struct {
A, B int
}
type Reply struct {
Result int
}
func (m *MathService) Multiply(args *Args, reply *Reply) error {
reply.Result = args.A * args.B
return nil
}
// Custom codec that includes Conn and RemoteAddr
type customCodec struct {
innerCodec rpc.ServerCodec
conn net.Conn
}
func (c *customCodec) ReadRequestHeader(r *rpc.Request) error {
return c.innerCodec.ReadRequestHeader(r)
}
func (c *customCodec) ReadRequestBody(body interface{}) error {
return c.innerCodec.ReadRequestBody(body)
}
func (c *customCodec) WriteResponse(r *rpc.Response, body interface{}) error {
return c.innerCodec.WriteResponse(r, body)
}
func (c *customCodec) Close() error {
return c.innerCodec.Close()
}
func (c *customCodec) Conn() net.Conn {
return c.conn
}
// Custom listener that returns a customConn
type customListener struct {
net.Listener
}
func (l *customListener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &customConn{Conn: conn}, nil
}
// Custom connection that embeds net.Conn
type customConn struct {
net.Conn
}
func (c *customConn) RemoteAddr() net.Addr {
return c.Conn.RemoteAddr()
}
// ReportRealIP is a function to report the real IP of the client
func ReportRealIP(conn net.Conn) {
fmt.Printf("Real IP: %s\n", conn.RemoteAddr().String())
// Perform additional operations with the real IP, if needed
}
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
}
// Wrap the connection with customConn
customConn := &customConn{Conn: conn}
// Report real IP
ReportRealIP(customConn)
// Create a customCodec with the wrapped connection
codec := &customCodec{innerCodec: jsonrpc.NewServerCodec(customConn), conn: customConn}
// Serve the connection with the customCodec in a new goroutine
go rpc.ServeCodec(codec)
}
}
在此示例中,我创建了一个名为 customCodec 的自定义 ServerCodec,它嵌入原始 ServerCodec 并在其实现中包含 net.Conn。此外,我还创建了一个返回自定义连接 (customConn) 的自定义侦听器 (customListener)。然后可以使用自定义连接调用ReportRealIP函数来获取真实IP。