用thrift實現多語言相互調用

1、ubuntu下thrift的安裝
1.下載源代碼
http://thrift.apache.org/download/
下載最新版本 thrift-0.8.0.tar.gz

2.安裝boost庫
sudo apt-get install libboost-dev libboost-dbg libboost-doc bcp libboost-*

3.安裝其餘相關工具包
sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev ant
若是須要支持java,須要安裝jdk,配置java環境變量。

4.解壓文件,進入目錄thrift-0.8.0安裝
./configure --with-cpp --with-boost --without-python --without-csharp --with-java --without-erlang --without-perl --with-php --without-php_extension --without-ruby --without-haskell  --without-go
make
sudo make install
要支持java,須要編譯生成jar包,到lib/java目錄下,執行 ant命令。將在lib/java/build目錄下生成libthrift-0.8.0.jar和libthrift-0.8.0-javadoc.jar。編譯過程當中,可能出錯,須要檢查lib/java/build/tools/maven-ant-tasks-2.1.3.jar是否正確下載。

5.測試
直接輸入thrift命令,看是否有用法提示 

2、thrift自帶的測試樣例
進入tutorial文件夾,shared.thrift和tutorial.thrift是接口定義文件。
thrift -r --gen java tutorial.thrift
thirft -r --gen cpp tutorial.thrift
執行這兩條命令能夠生成gen-java和gen-cpp兩個文件夾,這些是thrift編譯器自動生成的代碼。

而後到java目錄下,執行 ant命令,編譯成功後,在兩個不一樣的窗口下執行如下命令:
./JavaServer
./JavaClient simple

進入cpp目錄下,執行make命令,若是編譯出錯,第一個錯誤是
/usr/local/include/thrift/protocol/TBinaryProtocol.tcc:147:35: error: there are no arguments to ‘htons’ that depend on a template parameter, so a declaration of ‘htons’ must be available
則修改Makefile,加上編譯選項-DHAVE_NETINET_IN_H
server: CppServer.cpp
        g++   -DHAVE_NETINET_IN_H  -o CppServer -I${THRIFT_DIR} -I${BOOST_DIR}  -I../gen-cpp -L${LIB_DIR} -lthrift CppServer.cpp ${GEN_SRC}

client: CppClient.cpp
        g++   -DHAVE_NETINET_IN_H  -o CppClient -I${THRIFT_DIR} -I${BOOST_DIR}  -I../gen-cpp -L${LIB_DIR} -lthrift CppClient.cpp ${GEN_SRC}
編譯經過生,將生成CppClient和CppServer兩個可執行程序。一樣,在兩個不一樣的窗口執行如下命令:
./CppServer
./CppClient
並且java和c++的Client和Server均可以交叉運行。好比運行JavaServer和CppClient也能獲得一樣的結果。以此達到了多語言的相互調用。

3、Hello World
仿照tutorial,寫一個簡單的hello world。在tutorial平級目錄下,創建目錄hello,這裏只是爲了測試須要。
服務端用java,客戶端用java和c++。

1. 編寫tt.thrift
namespace java demo
namespace cpp demo

service Hello{
  string helloString(1:string para)
}

2. 編譯生成代碼
thrift -r --gen java tt.thrift
thrift -r --gen cpp tt.thrift
生成gen-java和gen-cpp兩個文件夾
gen-cpp下有以下文件
Hello.cpp  Hello.h  Hello_server.skeleton.cpp  tt_constants.cpp  tt_constants.h  tt_types.cpp  tt_types.h
其中Hello.h,Hello.cpp中定義了遠程調用的接口,實現了底層通訊。能夠在Hello.h中找到客戶端遠程調用須要用到的類HelloClient,調用方法:
void helloString(std::string& _return, const std::string& para);
這個跟thrift文件中申明的方法有點不必定,返回參數是經過引用傳回來的。
Hello_server.skeleton.cpp將實現Hello.h的服務端接口,若是要用c++做爲服務端,還須要將這個文件拷出去,重命名,實現類HelloHandler的方法helloString,遠程調用方法的業務邏輯也就寫在helloString中。可能還須要改main函數中的端口信息。
gen-java/demo下只有Hello.java一個文件,它定義了服務端和客戶端的接口,實現了底層的通訊。

3. 編寫java服務端和客戶端
仿照tutorial,在hello目錄下創建java目錄,將tutorial/java/下的一些文件和目錄拷到hello/java下
build.xml JavaClient  JavaServer  src
刪除src下全部文件,在src下編寫代碼。

1) HelloImpl.java 遠程過程調用的業務邏輯
import demo.*;
import org.apache.thrift.TException;

class HelloImpl implements Hello.Iface {
 public HelloImpl() {}
  public String helloString(String para) throws org.apache.thrift.TException {
       //各類業務邏輯 
        return "hello " + para;
 }
}

2) Server.java  服務端程序
import demo.*;
import java.io.IOException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer.Args;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

public class Server {
private void start() {
try {
    TServerSocket serverTransport = new TServerSocket( 7911);
    Hello.Processor processor = new Hello.Processor(new HelloImpl());
    Factory protFactory = new TBinaryProtocol.Factory(true, true);
    Args args = new Args(serverTransport);
    args.processor(processor);
    args.protocolFactory(protFactory);
    TServer server = new TThreadPoolServer(args);
    //TServer server = new TThreadPoolServer(processor, serverTransport, protFactory);
    System.out.println("Starting server on port 7911 ...");
    server.serve();

   } catch (TTransportException e) {
    e.printStackTrace();
   } catch (Exception e) {
    e.printStackTrace();
}
}

public static void main(String args[]) {
    Server srv = new Server();
    srv.start();
}
}

3) Client.java 客戶端程序
import demo.*;
import java.io.IOException;
import org.apache.thrift.*;
import org.apache.thrift.protocol.*;
import org.apache.thrift.transport.*;

public class Client {
      public static void main(String [] args) {
           try {
                    TTransport transport = new TSocket(" localhost",   7911);
                    TProtocol protocol = new TBinaryProtocol(transport);
                    Hello.Client client = new Hello.Client(protocol);
                    transport.open();
                    System.out.println("Client calls hello");
                    System.out.println( client.helloString("world"));
                    transport.close();
               } catch (TException x) {
                    x.printStackTrace();
               }
        }
}

4) 修改 build.xml
<project name=" hello" default=" hello" basedir=".">

  <description> Thrift Hello</description>

  <property name="src" location="src" />
  <property name="gen" location="../gen-java" />
  <property name="build" location="build" />

  <path id="libs.classpath">
    <fileset dir="../../lib/java/build">
      <include name="*.jar" />
      <exclude name="-test.jar" />
    </fileset>
    <fileset dir="../../lib/java/build/lib">
      <include name="*.jar" />
    </fileset>
  </path>
  <path id="build.classpath">
    <path refid="libs.classpath" />
    <pathelement path="${gen}" />
  </path>

  <target name="init">
    <tstamp />
    <mkdir dir="${build}"/>
  </target>

  <target name="compile" depends="init">
    <javac srcdir="${gen}" destdir="${build}" classpathref="libs.classpath" />
    <javac srcdir="${src}" destdir="${build}" classpathref="build.classpath" />
  </target>

  <target name=" hello" depends="compile">
    <jar jarfile=" hello.jar" basedir="${build}"/>
  </target>

  <target name="clean">
    <delete dir="${build}" />
    <delete file=" hello.jar" />
  </target>

</project>

5) 編譯
ant
將生成build文件夾
Client.class  demo  hello  HelloImpl.class  hello.jar  Server.class

6) 修改執行腳本
JavaClient
java -cp ../../lib/java/build/lib/*:../../lib/java/build/*: hello.jar Client
JavaServer
java -cp ../../lib/java/build/lib/*:../../lib/java/build/*: hello.jar Server

4. 編寫c++客戶端
一樣仿照tutorial,將tutorial/cpp中的Makefile和CppClient.cpp拷到hello/cpp下。

1) 將CppClient.cpp重命名爲Client.cpp,並修改
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>

#include <protocol/TBinaryProtocol.h>
#include <transport/TSocket.h>
#include <transport/TTransportUtils.h>

#include "../gen-cpp/Hello.h"
#include <string>

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace demo;

using namespace boost;

int main(int argc, char** argv) {
  shared_ptr<TTransport> socket(new TSocket(" localhost",   7911));
  shared_ptr<TTransport> transport(new TBufferedTransport(socket));
  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
   HelloClient client(protocol);

  try {
    transport->open();

    string ret;
     client.helloString(ret, "world");
    printf("%s\n", ret.c_str());

    transport->close();
  } catch (TException &tx) {
    printf("ERROR: %s\n", tx.what());
  }

}

2). 修改Makefile
BOOST_DIR = /usr/local/boost/include/boost-1_33_1/
THRIFT_DIR = /usr/local/include/thrift
LIB_DIR = /usr/local/lib

GEN_SRC = ../gen-cpp/tt_types.cpp ../gen-cpp/Hello.cpp

default: client

client: Client.cpp
        g++   -DHAVE_NETINET_IN_H  -o client -I${THRIFT_DIR} -I${BOOST_DIR}  -I../gen-cpp -L${LIB_DIR} -lthrift Client.cpp ${GEN_SRC}

clean:
        $(RM) -r client

3). 編譯
make
生成可執行文件client

5. 運行程序
運行服務端程序,java目錄下: ./JavaServer
運行客戶端程序,cpp目錄下: ./client
這樣c++程序經過 client.helloString(ret, "client") 能夠調用服務端的java接口String helloString(String para)。
從而實現了遠程多語言調用。

參考網頁
http://hi.baidu.com/qingxue0532/blog/item/4846cd3bb79c67e354e72389.html
http://blog.sina.com.cn/s/blog_8d3bcbdb01012ea8.html
http://wenku.baidu.com/view/f77bc1a6f524ccbff1218461.html
相關文章
相關標籤/搜索