Thrift在Android上的客户端实现

最近公司有新的业务需求,需要把大量计算放到服务器上,既要尽可能小的侵入业务,又要实现服务端的代码复用,领导提出用RPC协议来实现。对于没接触过服务器的我来说,听到这个也是一头雾水,不过好在网上有现成的资料,看了几份资料后,发现Android中的AIDL机制和RPC是有点相似的。如果你对AIDL机制有所了解,那么RPC对你来说会是很简单的。而本文讲述的Thrift框架则实现了RPC服务,并且可与服务器进行跨语言(C++, Java, Python, PHP等)通信。

关于Thrift的详解,请参看:和 Thrift 的一场美丽邂逅,本文基于该博客进行简化讲解,下文中的代码基于thrift-0.10.0版本。

〇、Demo说明

  1. 该Demo功能为:Android端传递字符串到服务端,服务端由Thrift把字符串反转后(模拟计算操作)返回给Android端
  2. 该Demo不考虑性能、线程、优化等内容,仅仅做最简单的Thrift通讯
  3. 通过该Demo,我个人对RPC或Thrift理解就是:客户端和服务端约定好接口,服务端实现接口,客户端根据接口传入参数,远程调用服务端的实现方法,从而实现远程的方法调用。Android中存在的AIDL就类似于RPC。

一、配置Thrift

1 . 下载Windows版本的thrift.exe文件:点我下载
2 . 把该文件重命名为thrift.exe,放置到一个英文路径下。(我放到了C:\Program Files\Tomcat文件夹中)
thrift.exe路径
3 . 把thrift.exe所在目录添加到环境变量中
添加环境变量

4 . 运行cmd,输入”thrift“后回车,来检查是否正确配置。如果配置正确,会显示如下提示:
配置正确

二、定义接口

1 . 建立thrift接口:桌面上新建文件ReverseIface.thrift,在该文件中按以下格式定义一个reverseString(1:string strParam)接口,注意该接口文件为thrift版的原始接口文件,并且string为小写。

    /**
    * 文件名为ReverseIface.thrift
    * 实现功能:创建一个服务接口service,用于反转字符串
    * 基于:thrift-0.10.0
    **/
    namespace java com.younghong.thriftTest //定义命名空间,和java工程的包名一致

    service ReverseIface{
            /**
            * 定义接口,参数中传入一个字符串
            * @param strParam 待反转的字符串
            */
            string reverseString(1:string strParam)
    }

2 . 把上面的thrift接口编译成java接口:运行cmd,输入“cd desktop”后回车,切换到ReverseIface.thrift所在的桌面路径。然后接着输入“thrift -gen java ReverseIface.thrift”后回车,会在桌面生成gen-java文件夹,该文件夹中的ReverseIface.java文件就是我们需要的java接口。
cmd命令
java接口

三、搭建服务端

1 . 建立Maven工程,在pom.xml文件中的<dependencies>标签中添加以下内容:

    <dependency>
        <groupId>org.apache.thrift</groupId>
        <artifactId>libthrift</artifactId>
        <version>0.10.0</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.5</version>
    </dependency>

2 . 把刚才的java接口文件ReverseIface.java拷贝到项目中,然后新建类ReverseImp,实现ReverseIface.Iface接口。也就是说,我们要在这里实现刚才定义的反转方法,让它能够在服务器端执行。

    package com.younghong.thriftTest;

    import java.util.Collections;

    import org.apache.thrift.TException;

    public class ReverseImp implements ReverseIface.Iface {

        /**
         * 我们在C中定义的接口,通过thrift编译后,成为了对应的java接口Iface
         * C接口中的方法,也对应的成为了java接口中的方法
         */
        public String reverseString(String strParam) throws TException {
            // 参数为空,返回空
            if (strParam == null || "".equals(strParam)) {
                return "";
            }
            StringBuilder sb = new StringBuilder();//反转拼接
            char[] charArray = strParam.toCharArray();//取出原字符数组
            for (int i = charArray.length - 1; i >= 0; i--) {//反向取值,存入sb中
                sb.append(charArray[i]);
            }
            return sb.toString();//返回反转结果
        }
    }

3 . 在程序入口main函数中,编写启动服务的代码 ,编写完成后启动服务端,我们的反转函数就在服务端待命了,等待远程调用。

    package com.younghong.thriftTest;

    import org.apache.thrift.TProcessorFactory;
    import org.apache.thrift.protocol.TBinaryProtocol;
    import org.apache.thrift.server.TNonblockingServer;
    import org.apache.thrift.server.TServer;
    import org.apache.thrift.transport.TFramedTransport;
    import org.apache.thrift.transport.TNonblockingServerSocket;
    import org.apache.thrift.transport.TTransportException;

    /**
     1. Hello world!
     2.  */
    public class App {

        public static void main(String[] args) {
            try {
                // 实现反转字符串的Processor,传入实现类ReverseImp
                ReverseIface.Processor processor = new ReverseIface.Processor(new ReverseImp());
                // 构建Thrift通信协议,设置其中的参数
                TNonblockingServerSocket socket = new TNonblockingServerSocket(8080);
                TNonblockingServer.Args arg = new TNonblockingServer.Args(socket);
                arg.protocolFactory(new TBinaryProtocol.Factory());
                arg.transportFactory(new TFramedTransport.Factory());
                arg.processorFactory(new TProcessorFactory(processor));
                // 根据设定好的参数,构建server,并启动server
                TServer server = new TNonblockingServer(arg);
                server.serve();
            } catch (TTransportException e) {
                e.printStackTrace();
            }
        }
    }

四、Android平台实现客户端远程调用

1 . 新建Android工程,gradle中引入thrift和javax注解

    compile 'org.apache.thrift:libthrift:0.10.0'
    compile 'org.glassfish.main:javax.annotation:4.0-b33'

2 .在MainActivity的布局中添加一个EditText和一个Button,EditText用于输入字符串,Button用于远程调用服务器的方法。
这里写图片描述

3 .把刚才的java接口文件ReverseIface.java拷贝到项目中,注意包名仍要保持一致。添加INTERNET权限,然后在MainActivity.java中添加如下代码实现远程调用:

package com.younghong.thriftdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    public void onClick(View view) {
        //获取输入框的信息
        EditText editText = (EditText) findViewById(R.id.editText);
        final String strParam = editText.getText().toString();
        //开启线程,执行网络远程调用
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //构建Thrift传输和协议
                    TTransport tTransport = getTTransport();
                    TProtocol protocol = new TBinaryProtocol(tTransport);
                    //构建客户端,传入字符串进行反转操作
                    ReverseIface.Client client = new ReverseIface.Client(protocol);
                    String reversedStr = client.reverseString(strParam);
                    System.out.println("原字符串=" + strParam + "\t反转结果=" + reversedStr);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    //构建Thrift传输协议
    private TTransport getTTransport() throws Exception {
        try {
            //主机、端口、超时
            TSocket tSocket = new TSocket("172.16.36.146", 8080, 5000);
            //根据socket构建thrift
            TTransport tTransport = new TFramedTransport(tSocket);
            if (!tTransport.isOpen()) {
                tTransport.open();
            }
            return tTransport;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

4 .安装apk到手机上,点击Button后,观看控制台,能看到“原字符串=Hello World! 反转结果=!dlroW olleH”的输出就证明远程调用成功。
这里写图片描述

五、总结

你可能会说直接用Http的形式不也能调用吗?对于Http来说,我们只能把数据封装成xml、json等形式,通过网络传输后再分别解析操作。而thrift实现RPC机制,完成了客户端对服务端方法的远程调用,无需拼接字符串等操作。

对于thrift,我们定义好方法的接口,然后在服务端实现接口,客户端指定服务端的网络地址和端口,然后就可以像调用普通方法那样来调用服务端的方法。本例中仅仅讲解了简单参数String类型,你也可以通过定义类类型,比如User来作为参数,无序xml化或json化,直接传递到服务端调用远程方法,就好像在调用本地方法一样简单。

至此,我们实现了简单的RPC调用,其中有不正确的地方欢迎留言指出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值