• Thrift笔记(五)--Thrift server源码分析


    从(四)server代码跟进

    public static void simple(MultiplicationService.Processor processor) {
            try {
                TServerTransport serverTransport = new TServerSocket(9090);
                TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
    
                System.out.println("Starting the simple server...");
                server.serve();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    跟进server.serve()

    public void serve() {
        try {
          serverTransport_.listen();
        } catch (TTransportException ttx) {
          LOGGER.error("Error occurred during listening.", ttx);
          return;
        }
    
        // Run the preServe event
        if (eventHandler_ != null) {
          eventHandler_.preServe();
        }
    
        setServing(true);
    
        while (!stopped_) {
          TTransport client = null;
          TProcessor processor = null;
          TTransport inputTransport = null;
          TTransport outputTransport = null;
          TProtocol inputProtocol = null;
          TProtocol outputProtocol = null;
          ServerContext connectionContext = null;
          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);
              if (eventHandler_ != null) {
                connectionContext = eventHandler_.createContext(inputProtocol, outputProtocol);
              }
              while (true) {
                if (eventHandler_ != null) {
                  eventHandler_.processContext(connectionContext, inputTransport, outputTransport);
                }
                if(!processor.process(inputProtocol, outputProtocol)) {
                  break;
                }
              }
            }
          } 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);
            }
          }
    
          if (eventHandler_ != null) {
            eventHandler_.deleteContext(connectionContext, inputProtocol, outputProtocol);
          }
    
          if (inputTransport != null) {
            inputTransport.close();
          }
    
          if (outputTransport != null) {
            outputTransport.close();
          }
    
        }
        setServing(false);
      }

    跟进accept方法

    protected TSocket acceptImpl() throws TTransportException {
        if (serverSocket_ == null) {
          throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
        }
        try {
          Socket result = serverSocket_.accept();
          TSocket result2 = new TSocket(result);
          result2.setTimeout(clientTimeout_);
          return result2;
        } catch (IOException iox) {
          throw new TTransportException(iox);
        }
      }

    由于(四)使用的是阻塞IO, 代码也可以看到阻塞直到有客户端连接

    跟进process()方法

    public boolean process(TProtocol in, TProtocol out) throws TException {
        TMessage msg = in.readMessageBegin();
        ProcessFunction fn = processMap.get(msg.name);
        if (fn == null) {
          TProtocolUtil.skip(in, TType.STRUCT);
          in.readMessageEnd();
          TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, "Invalid method name: '"+msg.name+"'");
          out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
          x.write(out);
          out.writeMessageEnd();
          out.getTransport().flush();
          return true;
        }
        fn.process(msg.seqid, in, out, iface);
        return true;
      }

    整体流程,readMessageBegin读客户端请求方法。请求方法在服务端没有注册,返回异常给客户端。如果有方法,对应方法处理。跟进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();
        TSerializable result = null;
        byte msgType = TMessageType.REPLY;
    
        try {
          result = getResult(iface, args);
        } catch (TTransportException ex) {
          LOGGER.error("Transport error while processing " + getMethodName(), ex);
          throw ex;
        } catch (TApplicationException ex) {
          LOGGER.error("Internal application error processing " + getMethodName(), ex);
          result = ex;
          msgType = TMessageType.EXCEPTION;
        } catch (Exception ex) {
          LOGGER.error("Internal error processing " + getMethodName(), ex);
          if(!isOneway()) {
            result = new TApplicationException(TApplicationException.INTERNAL_ERROR,
                "Internal error processing " + getMethodName());
            msgType = TMessageType.EXCEPTION;
          }
        }
    
        if(!isOneway()) {
          oprot.writeMessageBegin(new TMessage(getMethodName(), msgType, seqid));
          result.write(oprot);
          oprot.writeMessageEnd();
          oprot.getTransport().flush();
        }
      }

    跟进读取参数方法

    public void read(org.apache.thrift.protocol.TProtocol iprot, multiply_args struct) throws org.apache.thrift.TException {
            org.apache.thrift.protocol.TField schemeField;
            iprot.readStructBegin();
            while (true)
            {
              schemeField = iprot.readFieldBegin();
              if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
                break;
              }
              switch (schemeField.id) {
                case 1: // N1
                  if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
                    struct.n1 = iprot.readI32();
                    struct.setN1IsSet(true);
                  } else { 
                    org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
                  }
                  break;
                case 2: // N2
                  if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
                    struct.n2 = iprot.readI32();
                    struct.setN2IsSet(true);
                  } else { 
                    org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
                  }
                  break;
                default:
                  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
              }
              iprot.readFieldEnd();
            }
            iprot.readStructEnd();
    
            // check for required fields of primitive type, which can't be checked in the validate method
            struct.validate();
          }

    服务端跟进处理

    result = getResult(iface, args);

    继续跟进

    public multiply_result getResult(I iface, multiply_args args) throws org.apache.thrift.TException {
            multiply_result result = new multiply_result();
            result.success = iface.multiply(args.n1, args.n2);
            result.setSuccessIsSet(true);
            return result;
          }

    这里拿到结果, 最后写回给客户端

    if(!isOneway()) {
          oprot.writeMessageBegin(new TMessage(getMethodName(), msgType, seqid));
          result.write(oprot);
          oprot.writeMessageEnd();
          oprot.getTransport().flush();
        }

    这是最简单的一种方式,使用阻塞io, 二进制协议序列化。还有分阻塞, 压缩协议等。

  • 相关阅读:
    (转)ELK Stack 中文指南--性能优化
    (转)如何在CentOS / RHEL 7上安装Elasticsearch,Logstash和Kibana(ELK)
    (转)GlusterFS 01 理论基础,企业实战,故障处理
    (转)CentOS7.4环境下搭建--Gluster分布式集群存储
    (转)DB2性能优化 – 如何通过调整锁参数优化锁升级
    (转)架构师之DNS实战CentOS7VSCentOS6
    PHP:计算文件或数组中单词出现频率
    [获取行数]php读取大文件提供性能的方法,PHP的stream_get_line函数读取大文件获取文件的行数的方...
    Windows下配置环境变量和需不需要重启问题
    CENTOS 下安装APK反编译工具 APKTOOL
  • 原文地址:https://www.cnblogs.com/luckygxf/p/9379702.html
Copyright © 2020-2023  润新知