1. 程式人生 > >Ubuntu 16.04 原始碼安裝Thrift的過程記錄

Ubuntu 16.04 原始碼安裝Thrift的過程記錄

1、首先需要安裝依賴的軟體包 ,參考網址官方安裝說明

sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config

2、建立一個目錄,用git下載原始碼或者到網站下載最新的穩定版原始碼包下載地址

git clone https://github.com/apache/thrift.git

cd thrift

3、執行安裝步驟,簡化為 一下幾部分,如果不是通過git下載的,則不需要執行bootstrap.sh,參考

編譯原始碼過程

./bootstrap.sh
./configure
make
sudo make install

4、進行測試,編寫exchange.thrift檔案,檔案內容如下

#!/usr/local/bin/thrift --gen cpp

namespace cpp Test
namespace java com.thrift.test

service NucInfoExchange {
  string execute(1:string instruction)
  void push(1:string message)
}

5、生成C++和Java程式碼

thrift --gen cpp exchange.thrift
thrift --gen java exchange.thrift

這兩行命令將會在當前目錄下生成gen-cpp和gen-java兩個目錄,這兩個目錄裡面就是生成的C++和java程式碼

6、首先進入gen-cpp目錄,將生成的NucInfoExchange_server.skeleton.cpp拷貝為NucInfoExchange_server.cpp,並修改程式碼,執行如下命令

cd gen-cpp
cp NucInfoExchange_server.skeleton.cpp NucInfoExchange_server.cpp
gedit NucInfoExchange_server.cpp

由於我主要想測試ThreadPool模式,所以對程式碼進行了修改,主要是加入了Processor的克隆類,修改了main函式,程式碼如下

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "NucInfoExchange.h"
#include <thrift/concurrency/PlatformThreadFactory.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/TToString.h>
#include <thrift/stdcxx.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/PosixThreadFactory.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TThreadedServer.h>

#include <iostream>
#include <stdexcept>
#include <sstream>

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

using namespace  Test;

class NucInfoExchangeHandler : virtual public NucInfoExchangeIf {
 public:
  NucInfoExchangeHandler() {
    // Your initialization goes here
  }

  void execute(std::string& _return, const std::string& instruction) {
    // Your implementation goes here
    printf("execute\n");
  }

  void push(const std::string& message) {
    // Your implementation goes here
    printf("push\n");
  }

};


class NucInfoExchangeCloneFactory : virtual public NucInfoExchangeIfFactory {
 public:
  virtual ~NucInfoExchangeCloneFactory() {}
  virtual NucInfoExchangeIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
  {
    stdcxx::shared_ptr<TSocket> sock = stdcxx::dynamic_pointer_cast<TSocket>(connInfo.transport);
    cout << "Incoming connection\n";
    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
    return new NucInfoExchangeHandler;
  }
  virtual void releaseHandler( NucInfoExchangeIf* handler) {
    delete handler;
  }
};

int main(int argc, char **argv) {
/*  int port = 9898;
  ::apache::thrift::stdcxx::shared_ptr<NucInfoExchangeHandler> handler(new NucInfoExchangeHandler());
  ::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new NucInfoExchangeProcessor(handler));
  ::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
  ::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
  ::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

  TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);

*/
  const int workerCount = 4;

  ::apache::thrift::stdcxx::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
  threadManager->threadFactory(stdcxx::make_shared<PosixThreadFactory>());
  threadManager->start();


  TThreadPoolServer server(
    stdcxx::make_shared<NucInfoExchangeProcessorFactory>(stdcxx::make_shared<NucInfoExchangeCloneFactory>()),
    stdcxx::make_shared<TServerSocket>(9898),
    stdcxx::make_shared<TBufferedTransportFactory>(),
    stdcxx::make_shared<TBinaryProtocolFactory>(),
    threadManager);


  server.serve();
  return 0;
}

7、開始編譯,編寫Makefile檔案如下

GEN_SRC := NucInfoExchange.cpp exchange_constants.cpp exchange_types.cpp
GEN_OBJ := $(patsubst %.cpp,%.o, $(GEN_SRC))

THRIFT_DIR := /usr/local/include/thrift
BOOST_DIR := /usr/include/boost

INC := -I$(THRIFT_DIR) -I$(BOOST_DIR)

.PHONY: all clean

all: NucInfoExchange_server

%.o: %.cpp
	$(CXX) -Wall -O2 -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H $(INC) -c $< -o [email protected]

NucInfoExchange_server: NucInfoExchange_server.o $(GEN_OBJ)  
	$(CXX) $^ -o [email protected] -L/usr/local/lib -lthrift

clean:
	$(RM) *.o NucInfoExchange_server

執行make命令,編譯沒有問題,出現了怪異的連結錯誤如下

g++ -Wall -O2 -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -I/usr/local/include/thrift -I/usr/include/boost -c NucInfoExchange_server.cpp -o NucInfoExchange_server.o
g++ -Wall -O2 -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -I/usr/local/include/thrift -I/usr/include/boost -c NucInfoExchange.cpp -o NucInfoExchange.o
g++ -Wall -O2 -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -I/usr/local/include/thrift -I/usr/include/boost -c exchange_constants.cpp -o exchange_constants.o
g++ -Wall -O2 -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -I/usr/local/include/thrift -I/usr/include/boost -c exchange_types.cpp -o exchange_types.o
g++ NucInfoExchange_server.o NucInfoExchange.o exchange_constants.o exchange_types.o -o NucInfoExchange_server -L/usr/local/lib -lthrift
NucInfoExchange_server.o:在函式‘main’中:
NucInfoExchange_server.cpp:(.text.startup+0x1e9):對‘apache::thrift::server::TThreadPoolServer::TThreadPoolServer(boost::shared_ptr<apache::thrift::TProcessorFactory> const&, boost::shared_ptr<apache::thrift::transport::TServerTransport> const&, boost::shared_ptr<apache::thrift::transport::TTransportFactory> const&, boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> const&, boost::shared_ptr<apache::thrift::concurrency::ThreadManager> const&)’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:17: recipe for target 'NucInfoExchange_server' failed
make: *** [NucInfoExchange_server] Error 1

看錯誤是連結的時候找不到ThreadPoolServer類,不能啊,這個肯定有,難道是用git下載的版本太高了?刪除了所有的thrift檔案,在官網上又下載了最新的穩定版thrift-0.11.0.tar.gz ,解壓編譯後,繼續編譯這個例子,依然是同樣的錯誤,折騰的都快精神崩潰了,又仔細看了看錯誤,為啥用的全都是boost::shared_ptr呢,印象中編譯時候顯示的是std=C++11 啊,靈機一動,趕緊修改Makefile檔案如下

GEN_SRC := NucInfoExchange.cpp exchange_constants.cpp exchange_types.cpp
GEN_OBJ := $(patsubst %.cpp,%.o, $(GEN_SRC))

THRIFT_DIR := /usr/local/include/thrift
BOOST_DIR := /usr/include/boost

INC := -I$(THRIFT_DIR) -I$(BOOST_DIR)

.PHONY: all clean

all: NucInfoExchange_server

%.o: %.cpp
	$(CXX) -Wall -std=c++11 -O2 -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H $(INC) -c $< -o [email protected]

NucInfoExchange_server: NucInfoExchange_server.o $(GEN_OBJ)  
	$(CXX) $^ -o [email protected] -L/usr/local/lib -lthrift

clean:
	$(RM) *.o NucInfoExchange_server

大家仔細看,編譯時增加了一個 -std=c++11選項,趕緊執行make嘗試一下,OK,成功了

8、在另外一臺windows上寫個java測試的客戶端吧,測試程式碼如下

package com.thrift.test;

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 TestThrift {

	public static void main(String[] args) {
        System.out.println("客戶端啟動....");
        
        for(int i = 0; i < 100 ; i++){
        	TestThread ts = new TestThread();
        	Thread thread = new Thread(ts);
        	thread.start();
        	try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }

	}

}


class TestThread implements Runnable{

	public void run() {
        TTransport transport = null;
        try {
            transport = new TSocket("192.168.1.105", 9898, 30000);
            // 協議要和服務端一致
            TProtocol protocol = new TBinaryProtocol(transport);
            NucInfoExchange.Client client = new NucInfoExchange.Client(protocol);
            transport.open();
            String result = client.execute("哈哈!!!!");
            System.out.println(result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
		
	}
}	

9、終於大功告成了,折騰了大半天的時間,終於搞定了,baidu和bing都用了,沒有找到任何線索,所以趕緊記錄下來,免得日後忘記了,很不容易。希望也能幫到別人。