I am running a GRPC server (Server A) listening on a specific port. I want to be able to send a communication to another server (Server B), and have Server B record the incoming address of Server A's connection so that it may later contact Server A.
On Server A, I listen on a port and create a context like such:
lis, err := net.Listen("tcp", "0.0.0.0:6000")
ctx, cancel := context.WithTimeout(context.Background(),
10000*time.Millisecond)
Then create a connection like so:
connection, err = grpc.DialContext(ctx, server2Address,
grpc.WithInsecure(), grpc.WithBlock())
Before finally sending a message to an endpoint on Server B, which attempts to read the IP address of Server A's incoming connection
info, _ := peer.FromContext(ctx)
fmt.Printf(info.Addr.String()) // Returns a random port, NOT 6000,
However, the resulting port printed by Server B is random, like 62056 as opposed to 6000 as intended. My assumption is that, on Server A, GRPC dials from a random port - is it possible to force GRPC to dial from port 6000 as opposed to a random port?
You can specify the source port like this:
cc, err := grpc.Dial("127.0.0.1:6001", grpc.WithInsecure(),
grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
dst, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return nil, err
}
src := &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 6000,
}
return net.DialTCP("tcp", src, dst)
}))
However if your server is listening on the same port this will result in an error:
panic: dial tcp 127.0.0.1:6000->127.0.0.1:6001: bind: address already in use
A different approach would be to pass the address as metadata. On the client you do:
ctx := context.Background()
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs("address", "127.0.0.1:6000"))
res, err := grpc_health_v1.NewHealthClient(cc).Check(ctx, &grpc_health_v1.HealthCheckRequest{
Service: "test",
})
And on the server:
func (s *server) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) {
if md, ok := metadata.FromIncomingContext(ctx); ok {
addr := md.Get("address")
// addr == "127.0.0.1:6000"
}
return &grpc_health_v1.HealthCheckResponse{
Status: grpc_health_v1.HealthCheckResponse_SERVING,
}, nil
}
And a third approach would be to use streaming.