我很困惑这个问题。我有一个Apache Thrift 0.9.0客户端和服务器。客户端代码如下:
this.transport = new TSocket(this.server, this.port);
final TProtocol protocol = new TBinaryProtocol(this.transport);
this.client = new ZKProtoService.Client(protocol);
这很好用。但是,如果我尝试将传输包装在TFramedTransport
this.transport = new TSocket(this.server, this.port);
final TProtocol protocol = new TBinaryProtocol(new TFramedTransport(this.transport));
this.client = new ZKProtoService.Client(protocol);
我在客户端获得以下模糊(没有任何解释消息)异常。服务器端没有显示错误。
org.apache.thrift.transport.TTransportException
at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
at org.apache.thrift.transport.TFramedTransport.readFrame(TFramedTransport.java:129)
at org.apache.thrift.transport.TFramedTransport.read(TFramedTransport.java:101)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
at org.apache.thrift.protocol.TBinaryProtocol.readAll(TBinaryProtocol.java:378)
at org.apache.thrift.protocol.TBinaryProtocol.readI32(TBinaryProtocol.java:297)
at org.apache.thrift.protocol.TBinaryProtocol.readMessageBegin(TBinaryProtocol.java:204)
at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:69)
at com.blablabla.android.core.device.proto.ProtoService$Client.recv_open(ProtoService.java:108)
at com.blablabla.android.core.device.proto.ProtoService$Client.open(ProtoService.java:95)
at com.blablabla.simpleprotoclient.proto.ProtoClient.initializeCommunication(ProtoClient.java:411)
at com.blablabla.simpleprotoclient.proto.ProtoClient.doWork(ProtoClient.java:269)
at com.blablabla.simpleprotoclient.proto.ProtoClient.run(ProtoClient.java:499)
at java.lang.Thread.run(Thread.java:724)
如果我使用TCompactProtocol
代替TBinaryProtocol
,它也会失败。
在服务器端,我已经使用自己的类扩展了TProcessor
,因为我需要为此客户端重用现有的服务处理程序(服务器端IFace
实现):
@Override
public boolean process(final TProtocol in, final TProtocol out)
throws TException {
final TTransport t = in.getTransport();
final TSocket socket = (TSocket) t;
socket.setTimeout(ProtoServer.SOCKET_TIMEOUT);
final String clientAddress = socket.getSocket().getInetAddress()
.getHostAddress();
final int clientPort = socket.getSocket().getPort();
final String clientRemote = clientAddress + ":" + clientPort;
ProtoService.Processor<ProtoServiceHandler> processor = PROCESSORS
.get(clientRemote);
if (processor == null) {
final ProtoServiceHandler handler = new ProtoServiceHandler(
clientRemote);
processor = new ProtoService.Processor<ProtoServiceHandler>(
handler);
PROCESSORS.put(clientRemote, processor);
HANDLERS.put(clientRemote, handler);
ProtoClientConnectionChecker.addNewConnection(clientRemote,
socket);
}
return processor.process(in, out);
}
这就是我启动服务器端的方式:
TServerTransport serverTransport = new TServerSocket(DEFAULT_CONTROL_PORT);
TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(
serverTransport).processor(new ControlProcessor()));
Thread thControlServer = new Thread(new StartServer("Control", server));
thControlServer.start();
我有一些问题:
TFramedTransport
或TCompactProtocol
时,为什么会失败?如何解决这个问题?欢迎任何有关此问题的帮助。提前谢谢!
答案 0 :(得分:4)
我遇到了同样的问题,终于找到了答案。可以在服务器上设置传输类型,但是我在Web上找到的大多数教程和示例都不清楚这一点。查看TServer.Args
类的所有方法(或扩展TServer.Args
的其他服务器的args类)。有方法inputTransportFactory
和outputTransportFactory
。您可以使用new TFramedTransport.Factory()
作为每个方法的输入来声明服务器应使用的传输。在斯卡拉:
val handler = new ServiceStatusHandler
val processor = new ServiceStatus.Processor(handler)
val serverTransport = new TServerSocket(9090)
val args = new TServer.Args(serverTransport)
.processor(processor)
.inputTransportFactory(new TFramedTransport.Factory)
.outputTransportFactory(new TFramedTransport.Factory)
val server = new TSimpleServer(args)
println("Starting the simple server...")
server.serve()
请注意,如果您使用的是TAsyncClient
,则无法选择使用的传输方式。您必须使用TNonblockingTransport
,它只有一个标准实现TNonblockingSocket
,它在内部包装您在框架传输中使用的任何协议。它实际上并没有将您选择的协议包装在TFramedTransport
中,但它确实将帧的长度添加到它写入的内容中,并且期望服务器也预先设置响应的长度。在我找到的任何地方都没有记录,但如果您查看源代码并尝试使用不同的组合,您会发现使用TSimpleServer
时必须使用TFramedTransport
才能使用TNonblockingServer
异步客户端。
顺便说一下,还值得注意的是,文档会说TFramedTransport
必须在传输后的最外层使用TNonblockingServer.Args
。但是,示例并未在TFramedTransport
中显示此设置,但您仍然发现必须在客户端使用TNonblockingServer.Args
才能在服务器上成功执行rpc。这是因为TFramedTransport
默认情况下其输入和输出协议设置为AbstractNonblockingServerArgs
(您可以使用反射来检查这一点,以检查超类层次结构的字段或{{1的构造函数的源代码 - 您可以覆盖输入和输出传输,但服务器可能会因文档中讨论的原因而失败。
答案 1 :(得分:2)
如果框架出现问题,但它没有框架,那么你的两端都有一个不兼容的协议栈。选择以下选项之一:
一个好的经验法则是,总是在两端使用完全相同的协议/传输堆栈。在特定情况下它会爆炸,因为framed会添加一个包含大小的四字节标头随后的消息。如果服务器不使用framed,客户端发送的这些额外的四个字节将被解释(错误地)作为消息的一部分。
完成该答案中的示例代码 TNonblockingServer in thrift crashes when TFramedTransport opens适用于C ++,在服务器上添加框架应该与Java非常相似。
PS:是的,重新使用你的处理程序是完全可以的。典型的处理程序是无状态的东西。