使用thrift做爲go和C++中間rpc及問題

這兩天由於工做須要查了一些跨語言的rpc接口。我這裏指的是包含序列化和tcp交互的。ios

主要查了一下如下三類:git

1.ICE 這玩意不支持go,直接放棄。apache

2.GRPC,這玩意剛剛發佈,還且全面使用C++11特性,咱們生產環境目前還沒升級,他依賴於protobuf 3.0.0版本,這個仍是beta版,拿過來編譯了下,依賴google的gmock。個人虛擬機上連不上去,只能暫時做罷。ubuntu

3.Thrift,這個從0.9.1 就開始完美(官方)支持go語言了,那就拿這個操刀吧。bash

 

注:C++測試環境ubuntu12.04LTS  內核 3.2.0-23 GCC版本4.6.3  Go就在win7筆記本上跑的。socket

第一件事安裝thrift,從官網下載最新thrift0.9.2版本。tcp

編譯安裝參考 http://my.oschina.net/zc741520/blog/399049函數

libevent庫我這邊前段時間用到了就不用安裝了,使用的版本是2.0.22-stable測試

 

GO版本thrift從這個地址this

git-wip-us.apache.org/repos/asf/thrift.git/lib/go/thrift獲取哦 
git.apache.org/thrift.git/lib/go/thrift永遠超時。

thrift文件以下:

namespace cpp helloword
namespace go helloword

service Test
{
	string hello(1: string data);
}

我把world寫錯了...=_=!

thrift --gen cpp helloword.thrift  

thrift --gen go helloword.thrift

生成的C++文件麼有問題,go裏面要修改下test.go和contants.go的thrift庫的位置

import(
	"helloword"
	"fmt"
	"git-wip-us.apache.org/repos/asf/thrift.git/lib/go/thrift"
	"os"
	"net"
)

 

下面開始擼C++代碼了。

C++ server端代碼

 1 #include <thrift/concurrency/ThreadManager.h>
 2 #include <thrift/concurrency/PosixThreadFactory.h>
 3 #include <thrift/protocol/TBinaryProtocol.h>
 4 #include <thrift/server/TSimpleServer.h>
 5 #include <thrift/server/TThreadPoolServer.h>
 6 #include <thrift/server/TThreadedServer.h>
 7 #include <thrift/transport/THttpServer.h>
 8 #include <thrift/transport/TServerSocket.h>
 9 #include <thrift/concurrency/ThreadManager.h>
10 #include <thrift/concurrency/PosixThreadFactory.h>
11 #include <thrift/protocol/TBinaryProtocol.h>
12 #include <thrift/server/TSimpleServer.h>
13 #include <thrift/server/TThreadPoolServer.h>
14 #include <thrift/server/TThreadedServer.h>
15 #include <thrift/transport/THttpServer.h>
16 #include <thrift/transport/TServerSocket.h>
17 #include <thrift/transport/TTransportUtils.h>
18 #include <thrift/TToString.h>
19 #include <iostream>
20 #include <string>
21 #include "Test.h"
22 #include <boost/bind.hpp>
23 #include <boost/function.hpp>
24 #include <thrift/protocol/TBinaryProtocol.h>
25 #include <thrift/transport/TSocket.h>
26 #include <thrift/transport/TTransportUtils.h>
27 using namespace std;
28 using namespace apache::thrift;
29 using namespace apache::thrift::concurrency;
30 using namespace apache::thrift::protocol;
31 using namespace apache::thrift::transport;
32 using namespace apache::thrift::server;
33 using namespace ::apache::thrift;
34 using namespace ::apache::thrift::protocol;
35 using namespace ::apache::thrift::transport;
36 using namespace ::boost;
37 using namespace ::helloword;
38 using ::boost::bind;
39 
40 class TestHandler : virtual public TestIf {
41  public:
42   TestHandler() { }
43 
44   void hello(std::string& _return, const std::string& data) {
45 //    if(data=="ping")
46       printf("[%d] recv ping\n", (int)time(NULL));
47   _return = "pong";
48   printf("[%d] send pong\n", (int)time(NULL));
49 }};
50 
51 int main(int argc, char **argv) {
52   int port = 9000;
53   shared_ptr<TestHandler> handler(new TestHandler());
54   shared_ptr<TProcessor> processor(new TestProcessor(handler));
55   shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
56   shared_ptr<TTransportFactory> transportFactory(new TTransportFactory());
57   shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
58   TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
59   server.serve();
60   return 0;
61 }

C++ Client端代碼

 1 #include <iostream>
 2 #include <string>
 3 #include <thrift/protocol/TBinaryProtocol.h>
 4 #include <thrift/transport/TSocket.h>
 5 #include <thrift/transport/TTransportUtils.h>
 6 #include "Test.h"
 7 using namespace std;
 8 using namespace apache::thrift;
 9 using namespace apache::thrift::protocol;
10 using namespace apache::thrift::transport;
11 using namespace helloword;
12 int main(int argc,char ** argv) {
13         string server = "127.0.0.1";
14         if(argc>1)server= argv[1];
15         boost::shared_ptr<TTransport> socket(new TSocket(server, 9000));
16         boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
17         boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
18         TestClient client(protocol);
19 try {
20         transport->open();
21         string cao="haha";
22         client.hello(cao,cao);
23         cout << "Hello"<< cao << endl;
24 }
25 catch(apache::thrift::TApplicationException &e)
26 {
27 cout<<e.what()<<endl;
28 }
29         return 0;
30 }

 

編譯server端

g++ -o server server.cpp Test.cpp helloword_constants.cpp helloword_types.cpp -lthrift -lboost_system

編譯Client端

g++ -o client client.cpp Test.cpp helloword_constants.cpp helloword_types.cpp -lthrift -lboost_system

測試C++沒有問題。


寫GO的代碼:

GO server端

package main

import(
	"helloword"
	"fmt"
	"git-wip-us.apache.org/repos/asf/thrift.git/lib/go/thrift"
	"os"
	
)

const (
	NetworkAddr = "192.168.20.76:9000"
)

type Test struct{
}

func (this *Test) Hello(data string)(r string, err error){  //注意這裏,個人thrift代碼裏面寫的接口時小寫的hello 在test.go裏面被fmt成大寫。 這裏由於C++ 支持大小寫,而Go 默認對外導出函數是大寫,因此接口儘可能定義成大寫保持一致,否則容易出現 thrift 接口不存在異常
	fmt.Println("rec", data)
	r = data+"haha"
	fmt.Println("send", r)
	return
}

func main(){
	transportFactory := thrift.NewTTransportFactory()
    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
    //protocolFactory := thrift.NewTCompactProtocolFactory()
 
    serverTransport, err := thrift.NewTServerSocket(NetworkAddr)
    if err != nil {
        fmt.Println("Error!", err)
        os.Exit(1)
    }
 
    handler := &Test{}
    processor := helloword.NewTestProcessor(handler)
 
    server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
    fmt.Println("thrift server in", NetworkAddr)
    server.Serve()
}

GO client代碼

package main

import(
	"helloword"
	"fmt"
	"git-wip-us.apache.org/repos/asf/thrift.git/lib/go/thrift"
	"os"
	"net"
)

func main (){
	transportFactory := thrift.NewTTransportFactory()
	protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
	transport ,err := thrift.NewTSocket(net.JoinHostPort("127.0.0.1","9000"))
	
	if err != nil {
        fmt.Fprintln(os.Stderr, "error resolving address:", err)
        os.Exit(1)
    }
	
	 useTransport := transportFactory.GetTransport(transport)
	 client := helloword.NewTestClientFactory(useTransport, protocolFactory)
	if err := transport.Open(); err != nil {
        fmt.Fprintln(os.Stderr, "Error opening socket to server", " ", err)
        os.Exit(1)
    }
    defer transport.Close()
	
	for i := 0; i < 2; i++ {
        r1, e1 := client.Hello("hello")
        fmt.Println(i, "Call->", r1, e1)
    }
	
 
}

固然測試也沒有問題。

 

下面就是交叉訪問了。

固然基於以上代碼一樣沒有問題 。附上截圖。

C++ client端 與 GO server端

 

GO client VS C++ server 一樣沒有問題我就不截圖了。

相關文章
相關標籤/搜索