ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 使用TFramedTransport时的TTransportException

2019-08-25 11:00:42  阅读:218  来源: 互联网

标签:java thrift


我很困惑这个问题.我有一个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时为什么会失败?如何解决这个问题?

欢迎任何有关此问题的帮助.提前致谢!

解决方法:

我遇到了同样的问题,终于找到了答案.可以在服务器上设置传输类型,但是我在网上找到的大多数教程和示例都不清楚这一点.查看TServer.Args类的所有方法(或扩展TServer.Args的其他服务器的args类).有方法inputTransportFactory和outputTransportFactory.您可以使用新的TFramedTransport.Factory()作为每个方法的输入来声明服务器应该使用哪个传输.在scala中:

  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才能在服务器上成功执行rpc.这是因为TNonblockingServer.Args默认将其输入和输出协议设置为TFramedTransport(您可以使用反射来检查这一点,以检查超类层次结构的字段或AbstractNonblockingServerArgs构造函数的源代码 – 您可以覆盖输入和输出传输,但服务器可能会因文档中讨论的原因而失败.

标签:java,thrift
来源: https://codeday.me/bug/20190825/1718339.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有