c# - 使用机器名时 gRPC DNS 解析失败
问题描述
我是 gRPC 的新手,并试图通过使用此处cactuaroid 的聊天服务器/客户端示例来学习它。我已修改代码以显示 WPF 应用程序中长时间运行的任务的进度。所有代码都在 .NET 5 上运行,我使用的是最新版本的 gRPC 包。
该过程在使用计算机的 IP 地址时工作正常,但在为 gRPC 客户端使用计算机名称时,我收到“DNS 解析失败”异常(计算机名称为“skylake”):
RpcException: Status(StatusCode="Unavailable", Detail="DNS 解析失败服务: skylake:6001", DebugException="Grpc.Core.Internal.CoreErrorDetailException: {"created":"@1615312867.300000000","description":"解析器瞬时故障","file":"......\src\core\ext\filters\client_channel\client_channel.cc","file_line":2138,"referenced_errors":[{"created":"@ 1615312867.300000000","description":"服务的DNS解析失败: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 状态不是 ARES_SUCCESS qtype=AAAA name=skylake is_balancer=0: 无法联系 DNS 服务器","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 状态不是 ARES_SUCCESS qtype=A name=skylake is_balancer=0: 无法联系 DNS 服务器","file":"......\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.cc","file_line":716} ]}]}]}")\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 状态不是 ARES_SUCCESS qtype=A name=skylake is_balancer=0: 无法联系 DNS 服务器","file":"......\src\core\ext\filters\client_channel\resolver\dns\c_ares\ grpc_ares_wrapper.cc","file_line":716}]}]}]}")\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 状态不是 ARES_SUCCESS qtype=A name=skylake is_balancer=0: 无法联系 DNS 服务器","file":"......\src\core\ext\filters\client_channel\resolver\dns\c_ares\ grpc_ares_wrapper.cc","file_line":716}]}]}]}")\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.cc","file_line":716}]}]}]}")\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.cc","file_line":716}]}]}]}")
我验证我可以使用 telnet skylake 6001 到达该端口。我正在本地测试,客户端和服务器都在同一台机器上。奇怪的是,gRPC 服务器似乎与计算机名称一样好。它只是有问题的客户。
服务器代码:
[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);
}
}
客户端代码:
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());
}
}
进度写入方法:
while (inProgress)
{
progressServiceClient.Write(new GrpcServer.ProgressReport
{
Id = Task.Id.ToString(),
PercentDone = percentDone,
TimeRemain = timeRemain
}).Wait();
Thread.Sleep(500);
}
进度读取方法:
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();
});
解决方案
感谢@jdweng 为我指明了正确的方向,这是通过将DNS 后缀添加到主机名(在我的例子中为skylake.lan)来解决的。我们可以通过 IPInterfaceProperties.DnsSuffix 获取 DNS 后缀。
或者,(这可能更安全)我们可以使用正确的 IP 地址而不是主机名,方法是使用类似的.
推荐阅读
- python - 估计向量标量以接近另一个向量
- java - 使用 Java 中的多条记录验证数组 JSON 响应
- r - 删除状态为无效的行/保留状态为有效的行
- linux - shell 脚本:转换原始输出(从 dict 行到 csv)
- javascript - 要求指导以检测站点中的元素是否已更改
- css - 在 Material UI 中调整组件大小而不变形
- jupyter-notebook - Jupyter Notebook“密码或令牌”问题
- android - 创建 realase apk 时出现字体未找到 AAPT 错误
- c - 在图表中搜索一个值并打印它下面的值
- laravel - Laravel 8 Eloquent ORM 登录流程