Facebook Thrift SSH帧大小错误求助:如何修复该异常?
我最近在本地运行Facebook Thrift服务,用下面的测试代码尝试调用FCR(Command Runner)服务,但运行时碰到了连接错误,先来看看我的测试代码和报错信息:
测试代码
import asyncio from fbnet.command_runner.thrift_client import AsyncioThriftClient # Import FCR Thrift Types from fbnet.command_runner_asyncio.CommandRunner import ttypes as fcr_ttypes # Import FCR Service Client from fbnet.command_runner_asyncio.CommandRunner.Command import Client as FcrClient import getpass # Device Information hostname = 'my_vm' username = 'root' password = getpass.getpass('%s Password: ' % username) # Destination device device = fcr_ttypes.Device(hostname=hostname, username=username, password=password) async def run(cmd, device): async with AsyncioThriftClient(FcrClient, 'x.x.x.x',22 ) as client: res = await client.run(cmd, device) # type of res is `struct CommandResult` print(res.output) loop = asyncio.get_event_loop() loop.run_until_complete(run('uname -a', device))
报错信息
Frame size 1397966893 too large for THeaderProtocol
Traceback (most recent call last):
File "pgm1.py", line 28, in loop.run_until_complete(run('uname -a', device))
File "/usr/local/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete return future.result()
File "pgm1.py", line 23, in run res = await client.run(cmd, device)
thrift.transport.TTransport.TTransportException: Connection closed
问题分析与修复方案
这个错误的核心原因是客户端和服务端的Thrift协议不匹配,或者连接的端口压根不对——先重点说最可能的问题:
1. 检查并修正连接端口
你代码里连接的是22端口,这是SSH服务的默认端口啊!Thrift服务几乎不会用22端口运行,这大概率是问题根源。先确认你的FCR Thrift服务实际监听的端口(比如常见的Thrift端口是9090,或者自定义的其他端口),把代码里的22改成正确的端口号,比如:
async with AsyncioThriftClient(FcrClient, 'x.x.x.x', 9090) as client:
2. 显式指定匹配的协议类型
如果端口改对还是报错,那可能是客户端和服务端使用的Thrift协议不一致。默认的AsyncioThriftClient可能用的协议和服务端不匹配,你可以显式指定协议工厂:
- 如果服务端用的是
THeaderProtocol,就这么写:from thrift.protocol.THeaderProtocol import THeaderProtocolFactory async with AsyncioThriftClient(FcrClient, 'x.x.x.x', 正确端口, protocol_factory=THeaderProtocolFactory()) as client: - 如果服务端用的是
TBinaryProtocol,就换成对应的工厂类:from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory async with AsyncioThriftClient(FcrClient, 'x.x.x.x', 正确端口, protocol_factory=TBinaryProtocolFactory()) as client:
3. 调整帧大小限制(极端情况)
如果确认端口和协议都匹配,只是返回的结果帧大小超过了默认限制,可以调整THeaderProtocol的最大帧大小:
from thrift.protocol.THeaderProtocol import THeaderProtocolFactory # 比如设置最大帧为10MB factory = THeaderProtocolFactory(max_frame_size=10*1024*1024) async with AsyncioThriftClient(FcrClient, 'x.x.x.x', 正确端口, protocol_factory=factory) as client:
总结
最优先检查的是连接端口是否正确——把22换成Thrift服务实际监听的端口,这应该能解决绝大多数问题。如果还是不行,再排查协议匹配和帧大小的问题。
内容的提问来源于stack exchange,提问作者user9729049

