參考文章:1、http://www.kankanews.com/ICkengine/archives/54084.shtml
2、http://www.cnblogs.com/liping13599168/archive/2011/09/15/2176836.html
Golang內置了對RPC支持,但只能適用於go語言程序之間調用。Thrift是一種可伸縮的跨語言服務框架,它支持C++,C#,Java,Python,Go等多種語言。
thrift允許你定義一個簡單的定義文件中的數據類型和服務接口,以作為輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。
這種方式與微軟的WCF框架以及Android中的AIDL服務的做法很類似。
1、安裝Go語言的thrift包
參考文章1給出的地址是:go get git.apache.org/thrift.git/lib/go/thrift,但該地址現在似乎不能訪問了,請使用下面的命令:
go get github.com/apache/thrift/lib/go/thrift
2、下載腳本編譯器
下載地址:http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.1/thrift-0.9.1.exe
該編譯工具可將thrift腳本文件編譯為目標變成語言代碼。
3、創建腳本
腳本文件采用thrift自帶教程github.com\apache\thrift\tutorial中的shared.thrift和tutorial.thrift:
shared.thrift文件如下:
namespace go shared
struct SharedStruct {
1: i32 key
2: string value
}
service SharedService {
SharedStruct getStruct(1: i32 key)
}
tutorial.thrift文件如下:
include "shared.thrift"
namespace go tutorial
typedef i32 MyInteger
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
exception InvalidOperation {
1: i32 what,
2: string why
}
service Calculator extends shared.SharedService {
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
oneway void zip()
}
4、編譯腳本
分別執行 thrift -gen go x:\shared.thrift和thrift -gen go x:\tutorial.thrift 命令,參數go表示生成go代碼,可以根據實際情況使用csharp,java,python等參數。
5、示例代碼
下面我們使用C#語言實現的客戶端與Go語言實現的服務端通信,進行跨語言調用。
將第4步中生成的go代碼放到服務端目錄下,服務端代碼如下:
main.go文件
package main
import (
"crypto/tls"
"fmt"
"github.com/apache/thrift/lib/go/thrift"
"tutorial"
)
func main() {
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
transportFactory := thrift.NewTTransportFactory()
addr := "localhost:9090"
secure := false
if err := runServer(transportFactory, protocolFactory, addr, secure); err != nil {
fmt.Println("error running server:", err)
}
}
func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error {
var transport thrift.TServerTransport
var err error
if secure {
cfg := new(tls.Config)
if cert, err := tls.LoadX509KeyPair("server.crt", "server.key"); err == nil {
cfg.Certificates = append(cfg.Certificates, cert)
} else {
return err
}
transport, err = thrift.NewTSSLServerSocket(addr, cfg)
} else {
transport, err = thrift.NewTServerSocket(addr)
}
if err != nil {
return err
}
fmt.Printf("%T\n", transport)
handler := NewCalculatorHandler()
processor := tutorial.NewCalculatorProcessor(handler)
server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory)
fmt.Println("Starting the simple server... on ", addr)
return server.Serve()
}
handler.go文件使用原文件。
將第4步生成的c#代碼加入客戶端工程,並引用thrift.dll(該組件的代碼可在..\github.com\apache\thrift\tutorial\csharp下找到),如圖所示:
客戶端測試代碼如下:
class Program { static void Main(string[] args) { try { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); transport.Open(); try { client.ping(); Console.WriteLine("ping()"); int sum = client.add(1, 1); Console.WriteLine("1+1={0}", sum); Work work = new Work(); work.Op = Operation.DIVIDE; work.Num1 = 1; work.Num2 = 0; try { int quotient = client.calculate(1, work); Console.WriteLine("Whoa we can divide by 0"); } catch (InvalidOperation io) { Console.WriteLine("Invalid operation: " + io.Why); } work.Op = Operation.SUBTRACT; work.Num1 = 15; work.Num2 = 10; try { int diff = client.calculate(1, work); Console.WriteLine("15-10={0}", diff); } catch (InvalidOperation io) { Console.WriteLine("Invalid operation: " + io.Why); } SharedStruct log = client.getStruct(1); Console.WriteLine("Check log: {0}", log.Value); } finally { transport.Close(); } } catch (TApplicationException x) { Console.WriteLine(x.StackTrace); } Console.ReadKey(); } }
測試結果:
本文結束。源碼下載:thriftserver thriftclient