浅析RPC框架Thrift

  created  by  鱼鱼 {{tag}}
创建于 2021年04月11日 01:04:38 最后修改于 2022年03月04日 01:03:46

    Thrift是由Facebook开发的 RPC远程调用的框架,使用独有的Thrift协议进行可跨语言的远程调用。有点类似protobuf。

Thrift的简单使用

1.环境准备和依赖引入

    无论使用何种语言,首先要准备Thrift编译环境,可以去官网下载相应的Thrift执行文件,下文均以Windows为例。下载后可以选择性的配置环境变量,最终在shell中可执行Thrift。

    在项目中,预先准备好libthrift依赖,maven写法:

<dependency>
   <groupId>org.apache.thrift</groupId>
   <artifactId>libthrift</artifactId>
   <version>0.14.1</version>
</dependency>

2. IDL文件的定义

    例如:

定义一个testService.thrift(idl文件名不重要),一般都会定义在resources的thrift文件夹下:

  /**
   *  定义了命名空间 语言 其中命名空间就是java中package thrift是大小写敏感的
   */
namespace java com.example.demo.thrift
  /**
   *  这里的Service name(TestThriftService)便是后面生成的类名
   */
service TestThriftService
{
  /**
   *  可添加注释,最好在变量前标上数字
   */
   string getStr(1:string srcStr1, 2:string srcStr2),
   i32 getInt(1:i32 val1,2:i32 val2)
}

    这里定义了两个方法,分别返回字符串和int类型,在thrift的idl中,对于变量的定义如下:

  1. string, 字符串类型,注意是全部小写形式;例如:string aString;

  2. i16, 16位整形类型,例如:i16 aI16Val;

  3. i32,32位整形类型,对应C/C++/java中的int类型;例如:      I32  aIntVal;

  4. i64,64位整形,对应C/C++/java中的long类型;例如:I64 aLongVal;

  5. byte,8位的字符类型,对应C/C++中的char,java中的byte类型;例如:byte aByteVal;

  6. bool, 布尔类型,对应C/C++中的bool,java中的boolean类型; 例如:bool aBoolVal;

  7. double,双精度浮点类型,对应C/C++/java中的double类型;例如:double aDoubleVal;

  8. void,空类型,对应C/C++/java中的void类型;该类型主要用作函数的返回值,例如:void testVoid;

3.通过 IDL生成类文件

    当我们完成第一步环境准备后,就可以直接使用thrift执行下面的命令生成Java类:

thrift --gen <language> <Thrift filename>

    例如,将上面的thrift转为.java:

thrift --gen java testService.thrift

    便会自动在当前目录下生成目录和文件 com/example/demo/thrift/TestThriftService.java。

3.2通过 IDL生成类文件-使用maven插件

    通过shell命令生成java文件未免过于麻烦,尤其当idl很多时,执行略为繁琐,这时可以使用mavan插件maven-thrift-plugin完成这一操作,注意即使使用插件也需要满足Thrift环境,因为本质上依旧是通过命令行转换 。在pom.xml中配置:

<build>
      <plugins>
         <plugin>
            <groupId>org.apache.thrift.tools</groupId>
            <artifactId>maven-thrift-plugin</artifactId>
            <version>0.1.11</version>
            <configuration>
               <!--指定Thrift编译文件的目录和位置,设定环境变量便可不用指定-->
               <thriftExecutable>D://thrift</thriftExecutable>
               <!--指定待编译的  IDL文件目录,默认为src/main/thrift-->
               <thriftSourceRoot>src/main/resources/thrift</thriftSourceRoot>
               <!--在0.1.10版本后的plugin需要添加的参数-->
               <generator>java</generator> 
               <!--指定编译输出目录-->
               <outputDirectory>src/main/java</outputDirectory>
            </configuration>
         </plugin>
      </plugins>
   </build>

    然后通过执行plugin 的compile指令即可将文件直接编译转化为java类,注意有些版本需要添加<generator>java</generator>,否则可能会报错:[ERROR] thrift failed error: [FAILURE:generation:1] Error: unknown option java:hashcode。同时,如果我们像上面一样指定了编译输出目录为项目目录,会覆盖原有目录下的文件,所以可以保持默认配置,输出至target目录下,然后复制到我们想要的package下。

4.编写Thrift接口的实现类

    通过上面那步,我们已经获得了Thrift生成的Service类,如下图:

    接下来,我们写一个他的实现类,需要实现<原类名>.Iface:

public class TestThriftServiceImpl implements TestThriftService.Iface {

    @Override
    public String getStr(String srcStr1, String srcStr2) {
        System.out.println("str1:"+srcStr1+",str2:"+srcStr2);
        return srcStr1+srcStr2;
    }

    @Override
    public int getInt(int val1, int val2) {
        System.out.println("val1:"+val1+",val2:"+val2);
        return val1+val2;
    }
}

5.编写Thrift服务端(被调用方)并启动

    我们来参考一下Thrift官方文档的simple:

public class JavaServer {

    public static TestThriftServiceImpl testThriftServiceImpl;
    public static TestThriftService.Processor processor;

    public static void main(String [] args) {
        try {
            testThriftServiceImpl = new TestThriftServiceImpl();
            processor = new TestThriftService.Processor(testThriftServiceImpl);

            Runnable simple = new Runnable() {
                public void run() {
                    simple(processor);
                }
            };
            //可选的使用SSL证书运行服务,其实一般  RPC都是内部服务调用,可能SSL并不是标配
            Runnable secure = new Runnable() {
                public void run() {
                    secure(processor);
                }
            };

            new Thread(simple).start();
            //new Thread(secure).start();
        } catch (Exception x) {
            x.printStackTrace();
        }
    }

    public static void simple(TestThriftService.Processor processor) {
        try {
                //指定端口与Server类型
            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();
        }
    }
    /**
     * 使用SSL协议运行
     * */
    public static void secure(TestThriftService.Processor processor) {
        try {
            TSSLTransportParameters params = new TSSLTransportParameters();
            //需要指定一个证书文件
            params.setKeyStore("../../lib/java/test/.keystore", "thrift", null, null);
            TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params);
            TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

            System.out.println("Starting the secure server...");
            server.serve();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    在这里启动了一个监听9090端口的Thrift服务,只需要通过impl指定一个professor,然后通过professor指定一个server并启动服务即可。这里选用了最普遍的simpleServer,有关server的分类,我们下面再提。

6.编写Thrift客户端(调用发起方)并执行

public class Client {
    public static void main(String [] args) {

        if (args.length != 1) {
            System.out.println("Please enter 'simple' or 'secure'");
            System.exit(0);
        }

        try {
            TTransport transport;
            if (args[0].contains("simple")) {
                transport = new TSocket("localhost", 9090);
                transport.open();
            }
            else {
                TSSLTransportFactory.TSSLTransportParameters params = new TSSLTransportFactory.TSSLTransportParameters();
                params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS");
                transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params);
            }

            TProtocol protocol = new TBinaryProtocol(transport);
            TestThriftService.Client client = new TestThriftService.Client(protocol);
            //这里其实已经是远程调用,可以跟服务端分别启动并检查日志
            int result = client.getInt(1,2);
            System.out.println(result);
            String result2 = client.getStr("hello,","world");
            System.out.println(result2);
            transport.close();
        } catch (TException x) {
            x.printStackTrace();
        }
    }
}

    这里使用相同的ThriftService类,可以通过代码复用或是引入依赖,只要简单的指定host、端口和协议即可,此处使用了二进制的TBinaryProtocol,注意此处的协议需要与服务端匹配一致才可以,具体额匹配关系下面再提。

    分别先后启动并执行server和client我们可以分别观察到他们打印的日志:

clent:

server:

到这里,一个简单的Thrift demo便完成了。

Thrift的数据编解码协议、传输层模式和工作模式

    我们注意到上面在客户端中指定了通信协议TbinaryProtocol,这也是默认的协议。在服务端使用的是TSimpleServer,这也是最简单的服务器类型,实际不适用于大多情境。在服务端,我们可以使用不同种的服务器;在服务端和客户端通信中也可以使用不同的协议类型。

服务端工作模式分类

    服务器主要根据不同的线程模型进行分类,主要分为以下几类:

  1. TSimpleServer,普通的BIO web服务器,单线程,基本不会使用;

  2. TNonBlockingServer,全异步的NIO服务器,单线程使用IO多路复用,并发效率高于SimpleServer,但因为是单线程也不好用;

  3. THsHaServer,半同步的服务器,socket读取使用NIO,执行业务代码则是交由线程池,同样资源下相对吞吐较高;

  4. TThreadPoolServer,类似 Tomcat默认每连接一线程的线程模型,使用线程池,不易阻塞但相对资源占用较高;

  5. TThreadSelectorServer,标准的NIO模式,负责监听连接的和处理连接请求数据的均为线程池,综合比较下来,此工作模式一般为最佳。

    大致可分为阻塞和非阻塞两类服务端,上面已经展示了阻塞同步服务端的创建,以下是非阻塞服务端的创建代码:

//……
    
public static TestThriftServiceImpl testThriftServiceImpl;
public static TestThriftService.Processor processor;   
    
    testThriftServiceImpl = new TestThriftServiceImpl();
    processor = new TestThriftService.Processor(testThriftServiceImpl);
    Runnable secure = new Runnable() {
        public void run() {
            threadSelector(processor);
        }
    };
//……
public static void threadSelector(TestThriftService.Processor processor) {
    try {
        //这里使用了threadSelector模式
        TNonblockingServerTransport serverSocket=new TNonblockingServerSocket(9090);//传输层协议
        TThreadedSelectorServer.Args serverParams=new TThreadedSelectorServer.Args(serverSocket);

        serverParams.protocolFactory(new TBinaryProtocol.Factory()); //编码协议
        serverParams.processor(processor);
        TServer server=new TThreadedSelectorServer(serverParams); //TThreadedSelectorServer

        System.out.println("Starting the threadSelector server...");
        server.serve();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

客户端工作模式

    客户端调用也可以简单的分为同步和异步callback方式,以下是一个异步客户端的例子:

try {
    TNonblockingSocket transport=null;
    transport = new TNonblockingSocket("localhost", 9090); //传输层协议
    TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();  //编码协议
    TAsyncClientManager clientManager = new TAsyncClientManager();
    TProtocol protocol = new TBinaryProtocol(transport);
    TestThriftService.AsyncClient client = new TestThriftService.AsyncClient(factory,clientManager,transport);
    AsyncMethodCallback asyncMethodCallback = new AsyncMethodCallback() {    //异步callback
        @Override
        public void onComplete(Object response) {
            System.out.println("finished! return:"+response);
        }

        @Override
        public void onError(Exception exception) {
            System.out.println("error! ex:"+exception);
        }
    };
    //守护线程,注意主线程
    client.getInt(1,2,asyncMethodCallback);
} catch (TException | IOException x) {
    x.printStackTrace();
}

传输层分类

    Thrift有不同的传输层协议,该协议需要在服务端和客户端中保持一致,主要分为以下几种:

  1. TNonblockingTransport: 非阻塞的 Transport 的抽象类,底层使用 NIO

  2. TNonblockingSocket: TNonblockingTransport 的实现类,基于 SocketChannel 的 Transport,是非阻塞的

  3. TIOStreamTransport: 基于 IO 流的 Transport

  4. TSocket: TIOStreamTransport 的子类,底层使用 Socket

  5. TSimpleFileTransport:基于文件的 Transport,会将流写入文件或者从文件读取流

  6. TFileTransport: 基于文件的 Transport,会将流写入文件或者从文件读取流

  7. THttpClient:基于 HttpClient 或 Http URLConnection,会通过 HTTP 的方式发送请求,通常用于 TServlet 的服务端

  8. ByteBuffer: 基于 ByteBuffer 的 Transport

  9. TMemoryInputTransport:基于内存数组的 Transport,会从底层的数组读取,用于测试场景

  10. TMemoryBuffer:使用内存数组作为缓冲区的 Transport,用于测试场景

  11. TZlibTransport: 压缩的 Transport,会将流压缩后再发送

  12. AutoExpandingBufferReadTransport: 可扩展读缓冲区的 Transport,使用可变数组作为缓冲区

  13. AutoExpandingBufferWriteTransport: 可扩展写缓冲区的 Transport,使用可变数组作为缓冲区

  14. TSaslTransport:支持 SASL(Simple Authentication and Security Layer) 认证的 Transport,有两个实现类,用于客户端的TSaslClientTransport 和用于服务端的 TSaslServerTransport

  15. TFramedTransport:缓冲的 Transport,通过在前面带有4字节帧大小的消息来确保每次都完全读取消息

  16. TFastFramedTransport: 复用并扩展了读写缓冲区的 Transport,避免每次都创建新的 byte 数组

编解码协议


评论区
评论
{{comment.creator}}
{{comment.createTime}} {{comment.index}}楼
评论

浅析RPC框架Thrift

浅析RPC框架Thrift

    Thrift是由Facebook开发的 RPC远程调用的框架,使用独有的Thrift协议进行可跨语言的远程调用。有点类似protobuf。

Thrift的简单使用

1.环境准备和依赖引入

    无论使用何种语言,首先要准备Thrift编译环境,可以去官网下载相应的Thrift执行文件,下文均以Windows为例。下载后可以选择性的配置环境变量,最终在shell中可执行Thrift。

    在项目中,预先准备好libthrift依赖,maven写法:

<dependency>
   <groupId>org.apache.thrift</groupId>
   <artifactId>libthrift</artifactId>
   <version>0.14.1</version>
</dependency>

2. IDL文件的定义

    例如:

定义一个testService.thrift(idl文件名不重要),一般都会定义在resources的thrift文件夹下:

  /**
   *  定义了命名空间 语言 其中命名空间就是java中package thrift是大小写敏感的
   */
namespace java com.example.demo.thrift
  /**
   *  这里的Service name(TestThriftService)便是后面生成的类名
   */
service TestThriftService
{
  /**
   *  可添加注释,最好在变量前标上数字
   */
   string getStr(1:string srcStr1, 2:string srcStr2),
   i32 getInt(1:i32 val1,2:i32 val2)
}

    这里定义了两个方法,分别返回字符串和int类型,在thrift的idl中,对于变量的定义如下:

  1. string, 字符串类型,注意是全部小写形式;例如:string aString;

  2. i16, 16位整形类型,例如:i16 aI16Val;

  3. i32,32位整形类型,对应C/C++/java中的int类型;例如:      I32  aIntVal;

  4. i64,64位整形,对应C/C++/java中的long类型;例如:I64 aLongVal;

  5. byte,8位的字符类型,对应C/C++中的char,java中的byte类型;例如:byte aByteVal;

  6. bool, 布尔类型,对应C/C++中的bool,java中的boolean类型; 例如:bool aBoolVal;

  7. double,双精度浮点类型,对应C/C++/java中的double类型;例如:double aDoubleVal;

  8. void,空类型,对应C/C++/java中的void类型;该类型主要用作函数的返回值,例如:void testVoid;

3.通过 IDL生成类文件

    当我们完成第一步环境准备后,就可以直接使用thrift执行下面的命令生成Java类:

thrift --gen <language> <Thrift filename>

    例如,将上面的thrift转为.java:

thrift --gen java testService.thrift

    便会自动在当前目录下生成目录和文件 com/example/demo/thrift/TestThriftService.java。

3.2通过 IDL生成类文件-使用maven插件

    通过shell命令生成java文件未免过于麻烦,尤其当idl很多时,执行略为繁琐,这时可以使用mavan插件maven-thrift-plugin完成这一操作,注意即使使用插件也需要满足Thrift环境,因为本质上依旧是通过命令行转换 。在pom.xml中配置:

<build>
      <plugins>
         <plugin>
            <groupId>org.apache.thrift.tools</groupId>
            <artifactId>maven-thrift-plugin</artifactId>
            <version>0.1.11</version>
            <configuration>
               <!--指定Thrift编译文件的目录和位置,设定环境变量便可不用指定-->
               <thriftExecutable>D://thrift</thriftExecutable>
               <!--指定待编译的  IDL文件目录,默认为src/main/thrift-->
               <thriftSourceRoot>src/main/resources/thrift</thriftSourceRoot>
               <!--在0.1.10版本后的plugin需要添加的参数-->
               <generator>java</generator> 
               <!--指定编译输出目录-->
               <outputDirectory>src/main/java</outputDirectory>
            </configuration>
         </plugin>
      </plugins>
   </build>

    然后通过执行plugin 的compile指令即可将文件直接编译转化为java类,注意有些版本需要添加<generator>java</generator>,否则可能会报错:[ERROR] thrift failed error: [FAILURE:generation:1] Error: unknown option java:hashcode。同时,如果我们像上面一样指定了编译输出目录为项目目录,会覆盖原有目录下的文件,所以可以保持默认配置,输出至target目录下,然后复制到我们想要的package下。

4.编写Thrift接口的实现类

    通过上面那步,我们已经获得了Thrift生成的Service类,如下图:

    接下来,我们写一个他的实现类,需要实现<原类名>.Iface:

public class TestThriftServiceImpl implements TestThriftService.Iface {

    @Override
    public String getStr(String srcStr1, String srcStr2) {
        System.out.println("str1:"+srcStr1+",str2:"+srcStr2);
        return srcStr1+srcStr2;
    }

    @Override
    public int getInt(int val1, int val2) {
        System.out.println("val1:"+val1+",val2:"+val2);
        return val1+val2;
    }
}

5.编写Thrift服务端(被调用方)并启动

    我们来参考一下Thrift官方文档的simple:

public class JavaServer {

    public static TestThriftServiceImpl testThriftServiceImpl;
    public static TestThriftService.Processor processor;

    public static void main(String [] args) {
        try {
            testThriftServiceImpl = new TestThriftServiceImpl();
            processor = new TestThriftService.Processor(testThriftServiceImpl);

            Runnable simple = new Runnable() {
                public void run() {
                    simple(processor);
                }
            };
            //可选的使用SSL证书运行服务,其实一般  RPC都是内部服务调用,可能SSL并不是标配
            Runnable secure = new Runnable() {
                public void run() {
                    secure(processor);
                }
            };

            new Thread(simple).start();
            //new Thread(secure).start();
        } catch (Exception x) {
            x.printStackTrace();
        }
    }

    public static void simple(TestThriftService.Processor processor) {
        try {
                //指定端口与Server类型
            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();
        }
    }
    /**
     * 使用SSL协议运行
     * */
    public static void secure(TestThriftService.Processor processor) {
        try {
            TSSLTransportParameters params = new TSSLTransportParameters();
            //需要指定一个证书文件
            params.setKeyStore("../../lib/java/test/.keystore", "thrift", null, null);
            TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params);
            TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

            System.out.println("Starting the secure server...");
            server.serve();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    在这里启动了一个监听9090端口的Thrift服务,只需要通过impl指定一个professor,然后通过professor指定一个server并启动服务即可。这里选用了最普遍的simpleServer,有关server的分类,我们下面再提。

6.编写Thrift客户端(调用发起方)并执行

public class Client {
    public static void main(String [] args) {

        if (args.length != 1) {
            System.out.println("Please enter 'simple' or 'secure'");
            System.exit(0);
        }

        try {
            TTransport transport;
            if (args[0].contains("simple")) {
                transport = new TSocket("localhost", 9090);
                transport.open();
            }
            else {
                TSSLTransportFactory.TSSLTransportParameters params = new TSSLTransportFactory.TSSLTransportParameters();
                params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS");
                transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params);
            }

            TProtocol protocol = new TBinaryProtocol(transport);
            TestThriftService.Client client = new TestThriftService.Client(protocol);
            //这里其实已经是远程调用,可以跟服务端分别启动并检查日志
            int result = client.getInt(1,2);
            System.out.println(result);
            String result2 = client.getStr("hello,","world");
            System.out.println(result2);
            transport.close();
        } catch (TException x) {
            x.printStackTrace();
        }
    }
}

    这里使用相同的ThriftService类,可以通过代码复用或是引入依赖,只要简单的指定host、端口和协议即可,此处使用了二进制的TBinaryProtocol,注意此处的协议需要与服务端匹配一致才可以,具体额匹配关系下面再提。

    分别先后启动并执行server和client我们可以分别观察到他们打印的日志:

clent:

server:

到这里,一个简单的Thrift demo便完成了。

Thrift的数据编解码协议、传输层模式和工作模式

    我们注意到上面在客户端中指定了通信协议TbinaryProtocol,这也是默认的协议。在服务端使用的是TSimpleServer,这也是最简单的服务器类型,实际不适用于大多情境。在服务端,我们可以使用不同种的服务器;在服务端和客户端通信中也可以使用不同的协议类型。

服务端工作模式分类

    服务器主要根据不同的线程模型进行分类,主要分为以下几类:

  1. TSimpleServer,普通的BIO web服务器,单线程,基本不会使用;

  2. TNonBlockingServer,全异步的NIO服务器,单线程使用IO多路复用,并发效率高于SimpleServer,但因为是单线程也不好用;

  3. THsHaServer,半同步的服务器,socket读取使用NIO,执行业务代码则是交由线程池,同样资源下相对吞吐较高;

  4. TThreadPoolServer,类似 Tomcat默认每连接一线程的线程模型,使用线程池,不易阻塞但相对资源占用较高;

  5. TThreadSelectorServer,标准的NIO模式,负责监听连接的和处理连接请求数据的均为线程池,综合比较下来,此工作模式一般为最佳。

    大致可分为阻塞和非阻塞两类服务端,上面已经展示了阻塞同步服务端的创建,以下是非阻塞服务端的创建代码:

//……
    
public static TestThriftServiceImpl testThriftServiceImpl;
public static TestThriftService.Processor processor;   
    
    testThriftServiceImpl = new TestThriftServiceImpl();
    processor = new TestThriftService.Processor(testThriftServiceImpl);
    Runnable secure = new Runnable() {
        public void run() {
            threadSelector(processor);
        }
    };
//……
public static void threadSelector(TestThriftService.Processor processor) {
    try {
        //这里使用了threadSelector模式
        TNonblockingServerTransport serverSocket=new TNonblockingServerSocket(9090);//传输层协议
        TThreadedSelectorServer.Args serverParams=new TThreadedSelectorServer.Args(serverSocket);

        serverParams.protocolFactory(new TBinaryProtocol.Factory()); //编码协议
        serverParams.processor(processor);
        TServer server=new TThreadedSelectorServer(serverParams); //TThreadedSelectorServer

        System.out.println("Starting the threadSelector server...");
        server.serve();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

客户端工作模式

    客户端调用也可以简单的分为同步和异步callback方式,以下是一个异步客户端的例子:

try {
    TNonblockingSocket transport=null;
    transport = new TNonblockingSocket("localhost", 9090); //传输层协议
    TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();  //编码协议
    TAsyncClientManager clientManager = new TAsyncClientManager();
    TProtocol protocol = new TBinaryProtocol(transport);
    TestThriftService.AsyncClient client = new TestThriftService.AsyncClient(factory,clientManager,transport);
    AsyncMethodCallback asyncMethodCallback = new AsyncMethodCallback() {    //异步callback
        @Override
        public void onComplete(Object response) {
            System.out.println("finished! return:"+response);
        }

        @Override
        public void onError(Exception exception) {
            System.out.println("error! ex:"+exception);
        }
    };
    //守护线程,注意主线程
    client.getInt(1,2,asyncMethodCallback);
} catch (TException | IOException x) {
    x.printStackTrace();
}

传输层分类

    Thrift有不同的传输层协议,该协议需要在服务端和客户端中保持一致,主要分为以下几种:

  1. TNonblockingTransport: 非阻塞的 Transport 的抽象类,底层使用 NIO

  2. TNonblockingSocket: TNonblockingTransport 的实现类,基于 SocketChannel 的 Transport,是非阻塞的

  3. TIOStreamTransport: 基于 IO 流的 Transport

  4. TSocket: TIOStreamTransport 的子类,底层使用 Socket

  5. TSimpleFileTransport:基于文件的 Transport,会将流写入文件或者从文件读取流

  6. TFileTransport: 基于文件的 Transport,会将流写入文件或者从文件读取流

  7. THttpClient:基于 HttpClient 或 Http URLConnection,会通过 HTTP 的方式发送请求,通常用于 TServlet 的服务端

  8. ByteBuffer: 基于 ByteBuffer 的 Transport

  9. TMemoryInputTransport:基于内存数组的 Transport,会从底层的数组读取,用于测试场景

  10. TMemoryBuffer:使用内存数组作为缓冲区的 Transport,用于测试场景

  11. TZlibTransport: 压缩的 Transport,会将流压缩后再发送

  12. AutoExpandingBufferReadTransport: 可扩展读缓冲区的 Transport,使用可变数组作为缓冲区

  13. AutoExpandingBufferWriteTransport: 可扩展写缓冲区的 Transport,使用可变数组作为缓冲区

  14. TSaslTransport:支持 SASL(Simple Authentication and Security Layer) 认证的 Transport,有两个实现类,用于客户端的TSaslClientTransport 和用于服务端的 TSaslServerTransport

  15. TFramedTransport:缓冲的 Transport,通过在前面带有4字节帧大小的消息来确保每次都完全读取消息

  16. TFastFramedTransport: 复用并扩展了读写缓冲区的 Transport,避免每次都创建新的 byte 数组

编解码协议



浅析RPC框架Thrift2022-03-04鱼鱼

{{commentTitle}}

评论   ctrl+Enter 发送评论