<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Thrift RPC 框架指南 ### 認識Thrift框架 thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語言間無縫結合的、高效的服務。 - **thrift最初由facebook開發,07年四月開放源碼,08年5月進入apache孵化器。** - **thrift允許定義一個簡單的定義文件中的數據類型和服務接口,以作為輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。** - **類似Thrift的工具,還有Avro、protocol buffer,但相對于Thrift來講,都沒有Thrift支持全面和使用廣泛。** ### Thrift自下到上可以分為4層 Server(single-threaded, event-driven etc)服務器進程調度Processor(compiler generated)RPC接口處理函數分發,IDL定義接口的實現將掛接到這里面Protocol (JSON, compact etc)協議Transport(raw TCP, HTTP etc)網絡傳輸> Thrift實際上是實現了C/S模式,通過代碼生成工具將接口定義文件生成服務器端和客戶端代碼(可以為不同語言),從而實現服務端和客戶端跨語言的支持。用戶在Thirft描述文件中聲明自己的服務,這些服務經過編譯后會生成相應語言的代碼文件,然后用戶實現服務(客戶端調用服務,服務器端提服務)便可以了。其中protocol(協議層, 定義數據傳輸格式,可以為二進制或者XML等)和transport(傳輸層,定義數據傳輸方式,可以為TCP/IP傳輸,內存共享或者文件共享等)被用作運行時庫。 ### Thrift支持的傳輸及服務模型 ### 支持的傳輸格式: | 參數 | 描述 | |-----|-----| | TBinaryProtocol | 二進制格式 | | TCompactProtocol | 壓縮格式 | | TJSONProtocol | JSON格式 | | TSimpleJSONProtocol | 提供JSON只寫協議, 生成的文件很容易通過腳本語言解析。 | | TDebugProtocol | 使用易懂的可讀的文本格式,以便于debug | ### 支持的數據傳輸方式: | 參數 | 描述 | |-----|-----| | TSocket | 阻塞式socker | | TFramedTransport | 以frame為單位進行傳輸,非阻塞式服務中使用。 | | TFileTransport | 以文件形式進行傳輸。 | | TMemoryTransport | 將內存用于I/O. java實現時內部實際使用了簡單的ByteArrayOutputStream。 | | TZlibTransport | 使用zlib進行壓縮, 與其他傳輸方式聯合使用。當前無java實現。 | ### 支持的服務模型: | 參數 | 描述 | |-----|-----| | TSimpleServer | 簡單的單線程服務模型,常用于測試 | | TThreadPoolServer | 多線程服務模型,使用標準的阻塞式IO。 | | TNonblockingServer | 多線程服務模型,使用非阻塞式IO(需使用TFramedTransport數據傳輸方式) | # Thrift 下載及安裝 ### 如何獲取Thrift 1. 官網:[http://thrift.apache.org/](http://thrift.apache.org/) 1. golang的Thrift包: ~~~ go get git.apache.org/thrift.git/lib/go/thrift ~~~ ### 如何安裝Thrift mac下安裝Thrift,[參考上一篇介紹](http://blog.csdn.net/liuxinmingcode/article/details/45567241) 其他平臺安裝自行挖掘,呵呵。 安裝后通過 ~~~ liuxinmingMacBook-Rro#:thrift -version Thrift version 0.9.2 #看到這一行表示安裝成功 ~~~ # Golang、PHP通過Thrift調用 > 先發個官方各種語言DEMO地址 [https://git1-us-west.apache.org/repos/asf?p=thrift.git;a=tree;f=tutorial;h=d69498f9f249afaefd9e6257b338515c0ea06390;hb=HEAD](https://git1-us-west.apache.org/repos/asf?p=thrift.git;a=tree;f=tutorial;h=d69498f9f249afaefd9e6257b338515c0ea06390;hb=HEAD) ### Thrift的協議庫IDL文件 ### 語法參考 參考資料 [http://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html](http://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html) [http://my.oschina.net/helight/blog/195015](http://my.oschina.net/helight/blog/195015) #### 基本類型 - bool: **布爾值 (true or false), one byte** - byte: **有符號字節** - i16: **16位有符號整型** - i32: **32位有符號整型** - i64: **64位有符號整型** - double: **64位浮點型** - string: **Encoding agnostic text or binary string** > 基本類型中基本都是有符號數,因為有些語言沒有無符號數,所以Thrift不支持無符號整型。 #### 特殊類型 - binary: **Blob (byte array) a sequence of unencoded bytes** > 這是string類型的一種變形,主要是為java使用 #### struct結構體 thrift中struct是定義為一種對象,和面向對象語言的class差不多.,但是struct有以下一些約束: **struct不能繼承,但是可以嵌套,不能嵌套自己。** 1. 其成員都是有明確類型 2. 成員是被正整數編號過的,其中的編號使不能重復的,這個是為了在傳輸過程中編碼使用。 3. 成員分割符可以是逗號(,)或是分號(;),而且可以混用,但是為了清晰期間,建議在定義中只使用一種,比如C++學習者可以就使用分號(;)。 4. 字段會有optional和required之分和protobuf一樣,但是如果不指定則為無類型–可以不填充該值,但是在序列化傳輸的時候也會序列化進去, optional是不填充則部序列化。 required是必須填充也必須序列化。 5. 每個字段可以設置默認值 6. 同一文件可以定義多個struct,也可以定義在不同的文件,進行include引入。 ~~~ struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } ~~~ #### 容器(Containers) Thrift3種可用容器類型: - list(t): 元素類型為t的有序表,容許元素重復。 - set(t):元素類型為t的無序表,不容許元素重復。對應c++中的set,java中的HashSet,python中的set,php中沒有set,則轉換為list類型。 - map(t,t): 鍵類型為t,值類型為t的kv對,鍵不容許重復。對用c++中的map, Java的HashMap, PHP 對應 array, Python/Ruby 的dictionary。 > 容器中元素類型可以是除了service外的任何合法Thrift類型(包括結構體和異常)。為了最大的兼容性,map的key最好是thrift的基本類型,有些語言不支持復雜類型的key,JSON協議只支持那些基本類型的key。 > 容器都是同構容器,不失異構容器。 ### 實現Thrift TDL文件 batu.thrift文件: ~~~ /** * BatuThrift TDL * @author liuxinming * @time 2015.5.13 */ namespace go batu.demo namespace php batu.demo /** * 結構體定義 */ struct Article{ 1: i32 id, 2: string title, 3: string content, 4: string author, } const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} service batuThrift { list<string> CallBack(1:i64 callTime, 2:string name, 3:map<string, string> paramMap), void put(1: Article newArticle), } ~~~ ### 編譯IDL文件,生成相關代碼 ~~~ thrift -r --gen go batu.thrift thrift -r --gen php batu.thrift thrift -r --gen php:server batu.thrift #生成PHP服務端接口代碼有所不一樣 ~~~ ### Golang Service 實現 1.先按照golang的Thrift包 > go get git.apache.org/thrift.git/lib/go/thrift 2.將Thrift生成的開發庫復制到GOPATH中 > cp -r /Users/liuxinming/wwwroot/testphp/gen-go/batu $GOPATH/src 3.開發Go server端代碼(后面的代碼,目錄我們放在$GOPATH/src/thrift 中運行和演示) test.go文件: ~~~ package main import ( "batu/demo" #注意導入Thrift生成的接口包 "fmt" "git.apache.org/thrift.git/lib/go/thrift" "os" "time" ) const ( NetworkAddr = "127.0.0.1:9090" #監聽地址&端口 ) type batuThrift struct { } func (this *batuThrift) CallBack(callTime int64, name string, paramMap map[string]string) (r []string, err error) { fmt.Println("-->from client Call:", time.Unix(callTime, 0).Format("2006-01-02 15:04:05"), name, paramMap) r = append(r, "key:"+paramMap["a"]+" value:"+paramMap["b"]) return } func (this *batuThrift) Put(s *demo.Article) (err error) { fmt.Printf("Article--->id: %d\tTitle:%s\tContent:%t\tAuthor:%d\n", s.Id, s.Title, s.Content, s.Author) return nil } func main() { transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() //protocolFactory := thrift.NewTCompactProtocolFactory() serverTransport, err := thrift.NewTServerSocket(NetworkAddr) if err != nil { fmt.Println("Error!", err) os.Exit(1) } handler := &batuThrift{} processor := demo.NewBatuThriftProcessor(handler) server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory) fmt.Println("thrift server in", NetworkAddr) server.Serve() } ~~~ 4.運行go服務端(監聽9090端口) > liuxinmingdeMacBook-Pro:thrift liuxinming$ go run test.go thrift server in 127.0.0.1:9090 至此Go的Thrift服務端OK. ### Golang Client 實現 goClient.go文件: ~~~ package main import ( "batu/demo" "fmt" "git.apache.org/thrift.git/lib/go/thrift" "net" "os" "strconv" "time" ) const ( HOST = "127.0.0.1" PORT = "9090" ) func main() { startTime := currentTimeMillis() transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() transport, err := thrift.NewTSocket(net.JoinHostPort(HOST, PORT)) if err != nil { fmt.Fprintln(os.Stderr, "error resolving address:", err) os.Exit(1) } useTransport := transportFactory.GetTransport(transport) client := demo.NewBatuThriftClientFactory(useTransport, protocolFactory) if err := transport.Open(); err != nil { fmt.Fprintln(os.Stderr, "Error opening socket to "+HOST+":"+PORT, " ", err) os.Exit(1) } defer transport.Close() for i := 0; i < 10; i++ { paramMap := make(map[string]string) paramMap["a"] = "batu.demo" paramMap["b"] = "test" + strconv.Itoa(i+1) r1, _ := client.CallBack(time.Now().Unix(), "go client", paramMap) fmt.Println("GOClient Call->", r1) } model := demo.Article{1, "Go第一篇文章", "我在這里", "liuxinming"} client.Put(&model) endTime := currentTimeMillis() fmt.Printf("本次調用用時:%d-%d=%d毫秒\n", endTime, startTime, (endTime - startTime)) } func currentTimeMillis() int64 { return time.Now().UnixNano() / 1000000 } ~~~ goClient運行后結果: > liuxinmingdeMacBook-Pro:thrift liuxinming$ go run goClient.go GOClient Call-> [key:batu.demo value:test1] GOClient Call-> [key:batu.demo value:test2] GOClient Call-> [key:batu.demo value:test3] GOClient Call-> [key:batu.demo value:test4] GOClient Call-> [key:batu.demo value:test5] GOClient Call-> [key:batu.demo value:test6] GOClient Call-> [key:batu.demo value:test7] GOClient Call-> [key:batu.demo value:test8] GOClient Call-> [key:batu.demo value:test9] GOClient Call-> [key:batu.demo value:test10] 本次調用用時:1431583140857-1431583140855=2毫秒 ### PHP Client 實現 1. 首先去下載Thrift,git庫地址為:[https://github.com/apache/thrift](https://github.com/apache/thrift) 1. 新建項目目錄testphp,然后把thrift/lib/php/lib復制到testphp目錄下面 1. 復制生成的gen-php到testphp目錄下面 1. 客戶端代碼 ~~~ <?php /** * Thrift RPC - PHPClient * @author liuxinming * @time 2015.5.13 */ namespace batu\testDemo; header("Content-type: text/html; charset=utf-8"); $startTime = getMillisecond();//記錄開始時間 $ROOT_DIR = realpath(dirname(__FILE__).'/'); $GEN_DIR = realpath(dirname(__FILE__).'/').'/gen-php'; require_once $ROOT_DIR . '/Thrift/ClassLoader/ThriftClassLoader.php'; use Thrift\ClassLoader\ThriftClassLoader; use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TSocket; use Thrift\Transport\TSocketPool; use Thrift\Transport\TFramedTransport; use Thrift\Transport\TBufferedTransport; $loader = new ThriftClassLoader(); $loader->registerNamespace('Thrift',$ROOT_DIR); $loader->registerDefinition('batu\demo', $GEN_DIR); $loader->register(); $thriftHost = '127.0.0.1'; //UserServer接口服務器IP $thriftPort = 9090; //UserServer端口 $socket = new TSocket($thriftHost,$thriftPort); $socket->setSendTimeout(10000);#Sets the send timeout. $socket->setRecvTimeout(20000);#Sets the receive timeout. //$transport = new TBufferedTransport($socket); #傳輸方式:這個要和服務器使用的一致 [go提供后端服務,迭代10000次2.6 ~ 3s完成] $transport = new TFramedTransport($socket); #傳輸方式:這個要和服務器使用的一致[go提供后端服務,迭代10000次1.9 ~ 2.1s完成,比TBuffer快了點] $protocol = new TBinaryProtocol($transport); #傳輸格式:二進制格式 $client = new \batu\demo\batuThriftClient($protocol);# 構造客戶端 $transport->open(); $socket->setDebug(TRUE); for($i=1;$i<11;$i++){ $item = array(); $item["a"] = "batu.demo"; $item["b"] = "test"+$i; $result = $client->CallBack(time(),"php client",$item); # 對服務器發起rpc調用 echo "PHPClient Call->".implode('',$result)."<br>"; } $s = new \batu\demo\Article(); $s->id = 1; $s->title = '插入一篇測試文章'; $s->content = '我就是這篇文章內容'; $s->author = 'liuxinming'; $client->put($s); $s->id = 2; $s->title = '插入二篇測試文章'; $s->content = '我就是這篇文章內容'; $s->author = 'liuxinming'; $client->put($s); $endTime = getMillisecond(); echo "本次調用用時: :".$endTime."-".$startTime."=".($endTime-$startTime)."毫秒<br>"; function getMillisecond() { list($t1, $t2) = explode(' ', microtime()); return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); } $transport->close(); ~~~ PHP運行后結果: PHPClient Call->key:batu.demo value:1 PHPClient Call->key:batu.demo value:2 PHPClient Call->key:batu.demo value:3 PHPClient Call->key:batu.demo value:4 PHPClient Call->key:batu.demo value:5 PHPClient Call->key:batu.demo value:6 PHPClient Call->key:batu.demo value:7 PHPClient Call->key:batu.demo value:8 PHPClient Call->key:batu.demo value:9 PHPClient Call->key:batu.demo value:10 本次調用用時: :1431582183296-1431582183290=6毫秒 Go服務端看到打印數據: –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:1] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:2] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:3] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:4] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:5] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:6] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:7] –>from client Call: 2015-05-13 22:43:03 php client map[b:8 a:batu.demo] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:9] –>from client Call: 2015-05-13 22:43:03 php client map[a:batu.demo b:10] Article—>id: 1 Title:插入一篇測試文章 Content:我就是這篇文章內容 Author:liuxinming Article—>id: 2 Title:插入二篇測試文章 Content:我就是這篇文章內容 Author:liuxinming 完結,至此一個Golang的Thrift服務端 和 PHP的Thrift客戶端完成!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看