简体   繁体   中英

gRPC DNS resolution failed when using machine name

I am new to gRPC and trying to learn it by using the chat server/client sample from cactuaroid here . I've modified the code to show progress in a WPF app from a long running task. All code is running on .NET 5 and I'm using the latest versions of the gRPC packages.

The process is working fine when using the computer's IP address but when using computer name for the gRPC client, I'm getting a “DNS resolution failed” exception (computer name is “skylake”):

RpcException: Status(StatusCode="Unavailable", Detail="DNS resolution failed for service: skylake:6001", DebugException="Grpc.Core.Internal.CoreErrorDetailException: {"created":"@1615312867.300000000","description":"Resolver transient failure","file":"......\src\core\ext\filters\client_channel\client_channel.cc","file_line":2138,"referenced_errors":[{"created":"@1615312867.300000000","description":"DNS resolution failed for service: skylake:6001","file":"......\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.cc","file_line":362,"grpc_status":14,"referenced_errors":[{"created":"@1615312867.300000000","description":"C-ares status is not ARES_SUCCESS qtype=AAAA name=skylake is_balancer=0: Could not contact DNS servers","file":"......\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.cc","file_line":716,"referenced_errors":[{"created":"@1615312866.142000000","description":"C-ares status is not ARES_SUCCESS qty pe=A name=skylake is_balancer=0: Could not contact DNS servers","file":"......\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.cc","file_line":716}]}]}]}")

I verified that I could reach the port with telnet skylake 6001. I am testing locally, client and server both on the same machine. Oddly enough, the gRPC server seems to be just fine with the computer name. Its just the client that has an issue with it.

Server code:

[Export(typeof(IService))]
    public class ProgressServiceGrpcServer : Progress.ProgressBase, IService
    {
        [Import]
        private Logger m_logger = null;

        [Import]
        private ProgressService m_progressService = null;
        private readonly Empty m_empty = new Empty();

        private const int Port = 6001;
        private readonly Grpc.Core.Server m_server;

        public ProgressServiceGrpcServer()
        {
            m_server = new Grpc.Core.Server
            {
                Services =
                {
                    Progress.BindService(this)
                        .Intercept(new IpAddressAuthenticator())
                },
                Ports =
                {
                    new ServerPort("skylake", Port, ServerCredentials.Insecure)
                }
            };
        }

        public void Start()
        {
            m_server.Start();
            m_logger.Info("Started.");
        }

        public override async Task Subscribe(ChannelName channelName, IServerStreamWriter<ProgressReport> responseStream, ServerCallContext context)
        {
            context.CancellationToken.Register(() => m_logger.Info($"{context.Host} cancels subscription."));

            try
            {
                await m_progressService.GetProgressReportsAsObservable(channelName)
                    .ToAsyncEnumerable()
      .ForEachAwaitAsync(async (x) => await responseStream.WriteAsync(x), context.CancellationToken)
                    .ConfigureAwait(false);
            }
            catch (TaskCanceledException)
            {
                m_logger.Info($"{context.Host} unsubscribed.");
            }
        }

        public override Task<Empty> Write(ProgressReport request, ServerCallContext context)
        {
            m_logger.Info($"{context.Host} {request}");
            m_progressService.Add(request);
            return Task.FromResult(m_empty);
        }
    }

Client code:

public class ProgressServiceClient
    {
        private readonly Progress.ProgressClient m_client =
            new Progress.ProgressClient(
                new Channel("skylake”, 6001, ChannelCredentials.Insecure));

        public async Task Write(ProgressReport progressReport)
        {
            await m_client.WriteAsync(progressReport);
        }

        public IAsyncEnumerable<ProgressReport> ProgressReports(ChannelName channelName)
        {
            var call = m_client.Subscribe(channelName);

            return call.ResponseStream
                .ToAsyncEnumerable()
                .Finally(() => call.Dispose());
        }
    }

Progress write method:

while (inProgress)
            {
                progressServiceClient.Write(new GrpcServer.ProgressReport
                {
                    Id = Task.Id.ToString(),
                    PercentDone = percentDone,
                    TimeRemain = timeRemain
                }).Wait();

                Thread.Sleep(500);
            }

Progress read method:

m_progressService = new ProgressServiceClient();
ChannelName channelName = new ChannelName() { Id = id };

var cts = new CancellationTokenSource();
            _ = m_progressService.ProgressReports(channelName)
                .ForEachAsync((x) =>
                {
                    Log.Debug($"id: {x.Id} progress: {x.PercentDone}");
                }, cts.Token);

            this.Dispatcher.Invoke(() =>
            {
                Application.Current.Exit += (_, __) => cts.Cancel();
                this.Unloaded += (_, __) => cts.Cancel();
            });

Thanks to @jdweng for pointing me in the right direction, this was solved by adding the DNS suffix to the hostname (skylake.lan in my case). We can get the DNS suffix via IPInterfaceProperties.DnsSuffix.

Alternatively, (which might be safer) we can use the correct IP address instead of the host name by using something like that .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM