You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python gRPC TLS连接报错InactiveRpcError:无法连接所有地址

gRPC TLS连接报错:StatusCode.UNAVAILABLE 问题排查与解决

问题描述

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:45:44