Thrift原理学习-服务端

前言
    thrift是我所在公司使用的一款广泛的RPC框架,为了在之后的使用过程中,能够在遇到问题能够快速响应,解决。对了解其原理是很有必要的。今天先从服务端代码逻辑学起。 服务端实例 使用实例:开始之前首先看一个服务端使用过程中的一个例子:

namespace java com.wolfcoder.thrift
service Hello{
 string helloString(1:string para)
}
...
TProcessor tprocessor = new Hello.Processor<Hello.Iface>(new HelloWorldServiceImpl());//1
TServerSocket serverTransport = new TServerSocket(SERVER_PORT);//2
TServer.Args tArgs = new TServer.Args(serverTransport);//3
tArgs.processor(tprocessor);//4
tArgs.protocolFactory(new TBinaryProtocol.Factory());//5
TServer server = new TSimpleServer(tArgs);//6
server.serve();//7
...

1这段代码的目的就是注册该接口的方法列表。看下面的代码:

public Processor(I iface) {
  super(iface, getProcessMap(new HashMap<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));
}
private static <I extends Iface> Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> getProcessMap(Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {
  processMap.put("helloString", new helloString());
  return processMap;
}

getProcessMap方法体中已经生成了将所有的方法列表放置到map中的逻辑,最后会调用父类的构造方法,完成一个接口的注册。注册的内容包括:接口的具体实现类、方法列表。 2~5完成了服务端参数的包装。不细说。 6创建一个服务端实例,7开启一个服务线程接收服务。

public void serve() {
  stopped_ = false;
  try {
    serverTransport_.listen();
  } catch (TTransportException ttx) {
    LOGGER.error("Error occurred during listening.", ttx);
    return;
  }
  setServing(true);
  while (!stopped_) {
    try {
      client = serverTransport_.accept();
      if (client != null) {
        processor = processorFactory_.getProcessor(client);
        inputTransport = inputTransportFactory_.getTransport(client);
        outputTransport = outputTransportFactory_.getTransport(client);
        inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
        outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
        while (processor.process(inputProtocol, outputProtocol)) {}
      }
    } catch (TTransportException ttx) {
      // Client died, just move on
    } catch (TException tx) {
      if (!stopped_) {
        LOGGER.error("Thrift error occurred during processing of message.", tx);
      }
    } catch (Exception x) {
      if (!stopped_) {
        LOGGER.error("Error occurred during processing of message.", x);
      }
    }
  setServing(false);
}

serverTransport_:实际上就是我们在创建服务端实例时传入的参数,用来做socket通信。serverTransport_.listen():完成端口的监听。 下面会进入一个循环,在stoped_=false之前,都会进行判断服务。 serverTransport_.accept():阻塞接收客户端的连接。 processorFactory_.getProcessor(client):获取服务端配置的处理器。该处理器完成方法调用逻辑的封装。 具体的方法调用由Processor层来描述的。TProcessor只有一个方法process。

public boolean process(TProtocol in, TProtocol out) throws TException {
  TMessage msg = in.readMessageBegin();
  ProcessFunction fn = processMap.get(msg.name);
  fn.process(msg.seqid, in, out, iface);
  return true;
}

具体的方法执行流程中只需要关联两个协议层的对象,因为协议层对象包含了调用方调用信息的所有封装,同时协议层具备对结果封装的能力,所以在此只需要调用方和结果的封装对象即可。 in.readMessageBegin():读取调用方的请求头,包含的信息有:调用类型、方法名、请求号。 processMap.get(msg.name):在1中我们之后,在服务端代码执行最初会进行了一步注册过程,其中方法列表就保存在processMap中。key:方法名。value:方法描述对象(由thrift工具自动生成) ProcessFunction:对一个方法的描述,thrift工具生成一个方法对象的时候都会继承自该类。 方法的执行会委托给ProcessFunction#process来执行。

public final void process(int seqid, TProtocol iprot, TProtocol oprot, I iface) throws TException {
  T args = getEmptyArgsInstance();
  try {
    args.read(iprot);
  } catch (TProtocolException e) {
    iprot.readMessageEnd();
    TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());
    oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
    x.write(oprot);
    oprot.writeMessageEnd();
    oprot.getTransport().flush();
    return;
  }
  iprot.readMessageEnd();
  TBase result = getResult(iface, args);
  oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.REPLY, seqid));
  result.write(oprot);
  oprot.writeMessageEnd();
  oprot.getTransport().flush();
}

getEmptyArgsInstance():该方法的具体实现是由thrift工具为我们生成的,返回了对方法参数的描述,类型名称为:xxx_args args.read(iport):参数数据的read操作采用委托的方式移交给xxx_args类的成员变量schemes来完成的,包含两类schemes:StandardScheme、TupleScheme,同样thrift为我们生成了以上两个接口的实例。命名规则是methodname_argsStandardScheme。 getResult():该方法的方法信息是由thrfit来生成的。下面是生成的方法模板:

protected helloString_result getResult(I iface, helloString_args args) throws org.apache.thrift.TException {
  helloString_result result = new helloString_result();
  result.success = iface.helloString(args.para);
  return result;
}

逻辑一目了然,就是创建一个method_result对象,用于对方法执行结果封装,然后调用一下方法。最后返回结果就ok了。 之后的过程就是写回结果信息给客户端。 当一次远程调用完成之后,就会继续进入下一次等待,等待客户端的调用请求。直到stoped=true就会停止。 注:文中涉及到多个由thrift根据我们的IDL声明来生成的方法或者类,如果不了解可能会有点迷糊。下篇笔记将了解一下所有的生成方法和类的作用。Thrift学习-生成文件源码分析

转载于:https://my.oschina.net/ccqy66/blog/863826

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值