gRPC无法连接到所有地址,或者服务的DNS解析失败

2024-09-30 02:21:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在尝试为gRPC工作提供一个示例。我使用C#Asp.NET核心WebApi作为服务器,并尝试通过Python客户端连接到它

资源

我的原型文件:

syntax = "proto3";

service Example {
  rpc Insert (InsertRequest) returns (Empty);
  rpc Update (UpdateRequest) returns (Empty);
  rpc Delete (DeleteRequest) returns (Empty);
}

message InsertRequest {
    int32 Value = 1;
}

message UpdateRequest {
  string Id = 1;
  int32 Value = 2;
}

message DeleteRequest {
  string Id = 1;
}

message Empty { }

Python客户端:

import grpc

import example_pb2
import example_pb2_grpc

with grpc.insecure_channel('localhost:5001') as channel:
    stub = example_pb2_grpc.ExampleStub(channel)
    stub.Insert(example_pb2.InsertRequest(Value = 155))

问题

当我尝试运行Python客户端时,出现以下错误:

Traceback (most recent call last): File "gRPCExampleClient.py", line 10, in stub.Insert(example_pb2.InsertRequest(Value = 155)) File "C:\Python38\lib\site-packages\grpc_channel.py", line 923, in call return _end_unary_response_blocking(state, call, False, None) File "C:\Python38\lib\site-packages\grpc_channel.py", line 826, in _end_unary_response_blocking raise _InactiveRpcError(state) grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.UNAVAILABLE details = "failed to connect to all addresses" debug_error_string = "{"created":"@1612810257.299000000","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":5391,"referenced_errors":[{"created":"@1612810257.299000000","description":"failed to connect to all addresses","file":"src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc","file_line":398,"grpc_status":14}]}"

到目前为止我试过什么

  • 为我的Kestrel服务器显式启用HTTP/2
  • 已验证服务器是否与C#gRPC客户端一起工作
    • C#客户端使用与Python客户端相同的原型文件(C#客户端工作正常,可以与服务器通信)
    class Program
    {
        static void Main(string[] args)
        {
            var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var client = new Example.ExampleClient(channel);

            client.Insert(new InsertRequest() { Value = 155 });

            Console.ReadKey(true);
        }
    }
  • 试图在我的Python客户端(with grpc.insecure_channel('https://localhost:5001') as channel:)中使用“https://”方案。执行此操作时,我收到以下错误消息:

Traceback (most recent call last): File "gRPCExampleClient.py", line 10, in stub.Insert(example_pb2.InsertRequest(Value = 155)) File "C:\Python38\lib\site-packages\grpc_channel.py", line 923, in call return _end_unary_response_blocking(state, call, False, None) File "C:\Python38\lib\site-packages\grpc_channel.py", line 826, in _end_unary_response_blocking raise _InactiveRpcError(state) grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.UNAVAILABLE details = "DNS resolution failed for service: https://localhost:5001" debug_error_string = "{"created":"@1612809227.889000000","description":"Resolver transient failure","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":2141,"referenced_errors":[{"created":"@1612809227.889000000","description":"DNS resolution failed for service: https://localhost:5001","file":"src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc","file_line":201,"grpc_status":14,"referenced_errors":[{"created":"@1612809227.889000000","description":"OS Error","file":"src/core/lib/iomgr/resolve_address_windows.cc","file_line":95,"os_error":"No such host is known.\r\n","syscall":"getaddrinfo","wsa_error":11001}]}]}"

  • 在此之后,我尝试将环境变量GRPC_DNS_RESOLVER设置为native。遗憾的是,错误依然存在
from os import environ

environ["GRPC_DNS_RESOLVER"] = "native"
  • 尝试使用127.0.0.10.0.0.0加上和不加https://方案而不是localhost

杂项信息

我希望我只是错过了一些明显的东西,谢谢你的阅读和帮助


Tags: pyhttpsclientlocalhost客户端grpcvalueexample
2条回答

我终于明白了。根本问题是我的服务器配置不匹配。由于C#客户端自动检测由dotnet设置的ASP.NET核心开发证书,因此它将能够安全地连接到服务器。所有其他脚本语言(如python和go)将无法执行此操作,并拒绝连接,因为无法验证证书。(这是完全正确的,它仍然只是一个用于调试的自签名证书)

简而言之:您不能不安全地连接到gRPC服务器,除非它被明确设置为通过http/2服务不安全的http请求

因此,我们现在有两种选择:

  1. 显式地为脚本客户端提供证书公钥,以便他们知道可以信任我们的服务器
  2. 使用HTTP/2以非SSL模式启动服务器

一,

为了导出我的asp.net核心开发证书,我使用了certmgr。 使用此工具,我们可以将dev cert的公钥部分导出为.cer文件。 在此之后,我们只需告诉客户建立安全连接,并根据刚刚导出的公钥进行验证:

with open('../dev-cert.cer', 'rb') as f: #manually import public key of localhost ASP.NET Core dev certioficate (exported with certmgr)
        credentials = grpc.ssl_channel_credentials(f.read())
with grpc.secure_channel('localhost:5001', credentials) as channel:
    stub = example_pb2_grpc.ExampleStub(channel)
    stub.Insert(example_pb2.InsertRequest(Value = 155))

我也在go中测试了所有这些(以验证这不仅仅是python库的问题)

func main() {
    creds, err := credentials.NewClientTLSFromFile("../dev-cert.cer", "")
    if err != nil {
        log.Fatalf("could not process the credentials: %v", err)
    }

    conn, err := grpc.Dial("localhost:5001", grpc.WithTransportCredentials(creds))

    if err != nil {
        log.Fatalf("did not connect: %s", err)
    }
    defer conn.Close()

    request := example_grpc_client.InsertRequest{
        Value: 123,
    }

    client := example_grpc_client.NewExampleClient(conn)

    _, err = client.Insert(context.Background(), &request)
    if err != nil {
        log.Fatalf("error sending message: %s", err)
    }
}

二,

这是我找到的第一个解决方案,但我不建议使用它,因为它只是一种变通方法。 通过配置我的服务器应用程序,将kestrel配置为在HTTP/2中启动,并提供不安全连接支持,我可以获得不安全连接:

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.ConfigureKestrel(options => 
                    {
                        options.ListenLocalhost(5001, o => o.Protocols = HttpProtocols.Http2);
                    });

                    webBuilder.UseStartup<Startup>();
                });

请参阅https://github.com/grpc/grpc/blob/master/doc/naming.md

“https”的使用不正确

相关问题 更多 >

    热门问题