基于Thrift的java和PHP互相调用范例

首先我们看看 Thrift是什么?

thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

是不是感觉很酷??那我们看看怎么玩的,网上关于 thrift 的范例不少,但是很多都千篇一律,很多都有点残缺, 下面我们就展示一下用java来做服务端, 然后客户端用java和php同时来写的例子。

运行环境:

win7  x64

JDK  1.8.X

PHP 5.6

其中java部分是在在 Itellj idea里面基于MAVEN构建的项目。

废话不多说,上码

1,首先在idea简历maven项目, pom.xml 添加如下类库

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.9.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.2</version>
        </dependency>
    </dependencies>

 

2, 建立 demoHello.thrift 文件内容为

namespace java com.kedacom.demo.thriftDemo
service  HelloWorldService {
    string sayHello(1:string username)
}

 这种文件是 thrift专用的 IDL文件(Interface Description Language (IDL)), 然后再用 thrift 来生成 java的通用服务代码,命令如下:

     thrift-0.9.3.exe -r -gen java demoHello.thrift

 thrift的WIN7可执行文件下载  http://archive.apache.org/dist/thrift/0.9.3/thrift-0.9.3.exe, 下载完设置下 系统path就可以了, 执行命令会在 同目录下生成 gen-java 文件夹,  里面的 com\kedacom\demo\thriftDemo 下的HelloWorldService.java 文件就是我们要用到的,这个文件是定义了我们的IDL接口引用逻辑的,是把这个RPC接口抽象出来,客户端可以连接调用

 

3, 然后在项目的  src/main/java 目录下建立新的package, 命名为  com.kedacom.demo.thriftDemo,把上面的 HelloWorldService.java 拷贝到packge的目录下面,  然后在此package新建类HelloClientDemo, HelloServerDemo, HelloWorldImpl,内容分别为

 

HelloClientDemo

package com.kedacom.demo.thriftDemo;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

public class HelloClientDemo {
    public static final String SERVER_IP = "localhost";
    public static final int SERVER_PORT = 8090;
    public static final int TIMEOUT = 30000;


    public void startClient(String userName) {
        TTransport transport = null;
        try {
            transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
            // 协议要和服务端一致
            TProtocol protocol = new TBinaryProtocol(transport);
            // TProtocol protocol = new TCompactProtocol(transport);
            // TProtocol protocol = new TJSONProtocol(transport);
            HelloWorldService.Client client = new HelloWorldService.Client(protocol);
            transport.open();
            String result = client.sayHello(userName);
            System.out.println("Thrify client result =: " + result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }


    public static void main(String[] args) {
        HelloClientDemo client = new HelloClientDemo();
        client.startClient("Jimmy");
    }
}

 

 

 

HelloServerDemo

package com.kedacom.demo.thriftDemo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

public class HelloServerDemo {
    public static final int SERVER_PORT = 8090;

    public void startServer() {
        try {
            System.out.println("HelloWorld TSimpleServer start ....");

            TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldImpl());
            TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            // tArgs.protocolFactory(new TCompactProtocol.Factory());
            // tArgs.protocolFactory(new TJSONProtocol.Factory());
            TServer server = new TSimpleServer(tArgs);
            server.serve();
        } catch (Exception e) {
            System.out.println("Server start error!!!");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HelloServerDemo server = new HelloServerDemo();
        server.startServer();
    }
}

 

HelloWorldImpl

package com.kedacom.demo.thriftDemo;
import org.apache.thrift.TException;
public class HelloWorldImpl implements HelloWorldService.Iface {

    public HelloWorldImpl() {
    }

    public String sayHello(String username) throws TException {
        // TODO Auto-generated method stub
        return "Hi," + username + " welcome,. this is Thrift demo!";
    }
}

 

至此我们的java版的thrift的服务端和客户端就完成了

执行  HelloServerDemo 显示 HelloWorld TSimpleServer start ....

执行  HelloClientDemo 显示  Thrify client result =: Hi,Jimmy welcome,. this is Thrift demo!

 

其中核心逻辑其实是在 执行类  HelloWorldImpl 里面, server和client的类只是按照 thrift的标准来写好逻辑即可, 服务端和客户端的类的标准可参考官方文档,下面我们贴下 PHP 的客户端实现代码

首先我们把第二步的 文件改成

namespace php helloworld
service  HelloWorldService {
    string sayHello(1:string username)
}

执行thrift命令之后,会生成 gen-php 目录

 

PHP客户端代码如下

#!/usr/bin/env php
<?php

namespace helloworld\php;

error_reporting(E_ALL);

//echo __DIR__; exit();

require_once '/opt/thrift_php/lib/Thrift/ClassLoader/ThriftClassLoader.php';

///**
use Thrift\ClassLoader\ThriftClassLoader;

//$GEN_DIR = realpath(dirname(__FILE__).'/..').'/gen-php';
$GEN_DIR = '/opt/thrift_php/mycode/gen-php';

$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', '/opt/thrift_php/lib');  //这个是thrift源码下载之后,这个目录thrift-0.9.3/lib/抽离出来的
//$loader->registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib');
//$loader->registerDefinition('shared', $GEN_DIR);
$loader->registerDefinition('helloworld', $GEN_DIR);
$loader->register();



use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TSocket;
use Thrift\Transport\THttpClient;
use Thrift\Transport\TBufferedTransport;
use Thrift\Exception\TException;
//**/


//$socket = new TSocket('localhost', 8090); 
$socket = new TSocket('192.168.17.1', 8090); 
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$client = new \helloworld\HelloWorldServiceClient($protocol);
//print_r($client);

$transport->open();
$str = $client->sayHello("jimmyxx");
echo $str;

$transport->close();

其中 $socket = new TSocket('192.168.17.1', 8090);  这句是服务端的IP地址和运行端口, 直接在linux下 PHP 执行此文件,显示   Hi,jimmyxx welcome,. this is Thrift demo! 成功调用了java的服务端代码, 是不是能感觉到一点点跨编程语言的远程RPC调用的魅力所在呢? 呵呵~~~ 范例简单明了,应用到我们实际项目里面还是要根据项目的具体情况进行一下架构设计, 比如我们就把PHP的客户端,服务端都集成在我们的MVC框架里面去了。

源码地址请访问github: https://github.com/halokid/thrift-java-php,  有用的话,记得star或者fork一下哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章