Python gRPC TLS连接报错InactiveRpcError:无法连接所有地址
问题描述
在Python中测试gRPC客户端与服务端,非安全通道运行稳定,但建立TLS连接时出现StatusCode.UNAVAILABLE错误,报错详情如下:
Message = <_InactiveRpcError of RPC that terminated with: status = StatusCode.UNAVAILABLE details = "failed to connect to all addresses" debug_error_string = "{"created":"@1690999363.720000000","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":3094,"referenced_errors":[{"created":"@1690999363.720000000","description":"failed to connect to all addresses","file":"src/core/lib/transport/error_utils.cc","file_line":163,"grpc_status":14}]}" > Source = F:\Work\PytService\ClientPy\ClientPy.py Stack trace: File "F:\Work\PytService\ClientPy\ClientPy.py", line 22, in run response = stub.SayHello(service_pb2.HelloRequest(name='you')) File "F:\Work\PytService\ClientPy\ClientPy.py", line 32, in <module> (Current frame) run() grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.UNAVAILABLE details = "failed to connect to all addresses" debug_error_string = "{"created":"@1690999363.720000000","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":3094,"referenced_errors":[{"created":"@1690999363.720000000","description":"failed to connect to all addresses","file":"src/core/lib/transport/error_utils.cc","file_line":163,"grpc_status":14}]}" >
当前环境:
- grpcio 1.51.1
- Python 3.9.17
已尝试操作:更换多种方式生成的证书(含openssl生成)、将证书加密方式从RSA改为P-256曲线,均未解决问题。
服务端代码
from concurrent import futures import logging import grpc import service_pb2 import service_pb2_grpc class Greeter(service_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return service_pb2.HelloReply(message='Hello, %s!' % request.name) def SayHelloAgain(self, request, context): return service_pb2.HelloReply(message=f'Hello again, {request.name}!') def serve(): port = '50051' server_host = 'localhost' server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) service_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) keyfile = 'server-key.pem' certfile = 'server-cert.pem' private_key = open(keyfile).read() certificate_chain = open(certfile).read() credentials = grpc.ssl_server_credentials( ((bytes(private_key, 'utf-8'), bytes(certificate_chain, 'utf-8'),),) ) server.add_secure_port('localhost:50001',credentials) server.start() print("Server started, listening on " + port) server.wait_for_termination() if __name__ == '__main__': logging.basicConfig() serve()
客户端代码
from __future__ import print_function import logging import grpc import grpc_tools import service_pb2 import service_pb2_grpc def run(): ca_cert = 'ca-cert.pem' root_certs = open(ca_cert).read() credentials = grpc.ssl_channel_credentials((bytes(root_certs, 'utf-8'))) with grpc.secure_channel('localhost:50051',credentials) as channel: stub = service_pb2_grpc.GreeterStub(channel) response = stub.SayHello(service_pb2.HelloRequest(name='you')) print("Greeter client received: " + response.message) response = stub.SayHelloAgain(service_pb2.HelloRequest(name='you1')) print("Greeter client received: " + response.message) if __name__ == '__main__': logging.basicConfig() run()
解决方案
核心问题是服务端与客户端的端口不匹配:
- 服务端调用
add_secure_port时绑定的是localhost:50001 - 客户端
secure_channel连接的是localhost:50051
步骤1:统一端口
修改服务端代码中的端口,与客户端保持一致:
# 把原来的localhost:50001改成50051 server.add_secure_port('localhost:50051', credentials)
步骤2:优化证书读取方式(可选但更严谨)
读取证书时直接用二进制模式打开,避免编码转换问题:
- 服务端修改证书读取代码:
private_key = open(keyfile, 'rb').read() certificate_chain = open(certfile, 'rb').read() # 此时不需要手动转bytes,直接传入即可 credentials = grpc.ssl_server_credentials( ((private_key, certificate_chain,),) )
- 客户端修改证书读取代码:
root_certs = open(ca_cert, 'rb').read() credentials = grpc.ssl_channel_credentials(root_certs)
步骤3:验证证书有效性
确保server-cert.pem是由ca-cert.pem签发的,且证书中的CN(通用名称)与服务端绑定的主机名(这里是localhost)一致。
修改完成后重启服务端和客户端,TLS连接即可正常运行。
内容的提问来源于stack exchange,提问作者Raphael Ambrosius
相关产品推荐
相关产品推荐

