結論
context
の中にpeer
の情報があるのでそこにnet.Addr
が入っている。
import (
"google.golang.org/grpc/peer"
)
func foo(ctx context.Context, ...) {
var addr string
if pr, ok := peer.FromContext(ctx); ok {
addr = pr.Addr.String()
}
}
詳細
gRPCのgo実装であるgrpc-goはサーバ側でリクエストを受け取ってprotobufで生成されたハンドラを呼び出す部分とhttp2自体の実装部分とに分かれています。前者はserver.go、後者はhtt2_server.goになります。
Remote IPは接続元の情報(Peer)としてhttp2の実装側でstreamの中のcontextに格納されています。格納しているのはここ。
あとはハンドラの第一引数としてcontext.Context
が渡されるのでpeer.FromContext(ctx)
でPeerを取得します。peerのAddrがnet.Addr
なのでそのままString()でも良いですが、IPアドレスのみを取得したい場合は*net.TCPAddr
に変換すると良いでしょう。
import (
"google.golang.org/grpc/peer"
)
func (s *EchoServer) Echo(ctx context.Context, in *echo.EchoRequest) (*echo.EchoResponse, error) {
var addr string
if pr, ok := peer.FromContext(ctx); ok {
if tcpAddr, ok := pr.Addr.(*net.TCPAddr); ok {
addr = tcpAddr.IP.String()
} else {
addr = pr.Addr.String()
}
}
log.Printf("remote addr: %v", addr)
return &echo.EchoResponse{Message: in.Message}, nil
}