zoukankan      html  css  js  c++  java
  • thrift demo

    基于上一篇博客,安装thrift complier之后,就需要进行跑跑程序,来看看是否如同预期的那种效果。

    前面的thrift compiler的主要作用,其实就是为了IDL的,就是防止客户端和服务端的接口定义不同,基于IDL操作,最大限度的满足高效准确的实现服务的定义和实现。

    1. 首先定义.thrift扩展名的文件,有tutorial.thrift和shared.thrift,其内容如下:

    shared.thrift

     1 /*
     2  * Licensed to the Apache Software Foundation (ASF) under one
     3  * or more contributor license agreements. See the NOTICE file
     4  * distributed with this work for additional information
     5  * regarding copyright ownership. The ASF licenses this file
     6  * to you under the Apache License, Version 2.0 (the
     7  * "License"); you may not use this file except in compliance
     8  * with the License. You may obtain a copy of the License at
     9  *
    10  *   http://www.apache.org/licenses/LICENSE-2.0
    11  *
    12  * Unless required by applicable law or agreed to in writing,
    13  * software distributed under the License is distributed on an
    14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15  * KIND, either express or implied. See the License for the
    16  * specific language governing permissions and limitations
    17  * under the License.
    18  */
    19 
    20 /**
    21  * This Thrift file can be included by other Thrift files that want to share
    22  * these definitions.
    23  */
    24 
    25 namespace cpp shared
    26 namespace d share // "shared" would collide with the eponymous D keyword.
    27 namespace dart shared
    28 namespace java shared
    29 namespace perl shared
    30 namespace php shared
    31 namespace haxe shared
    32 
    33 struct SharedStruct {
    34   1: i32 key
    35   2: string value
    36 }
    37 
    38 service SharedService {
    39   SharedStruct getStruct(1: i32 key)
    40 }
    View Code

    tutorial.thrift

      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the
      7  * "License"); you may not use this file except in compliance
      8  * with the License. You may obtain a copy of the License at
      9  *
     10  *   http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing,
     13  * software distributed under the License is distributed on an
     14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15  * KIND, either express or implied. See the License for the
     16  * specific language governing permissions and limitations
     17  * under the License.
     18  */
     19 
     20 # Thrift Tutorial
     21 # Mark Slee (mcslee@facebook.com)
     22 #
     23 # This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
     24 # first thing to notice is that .thrift files support standard shell comments.
     25 # This lets you make your thrift file executable and include your Thrift build
     26 # step on the top line. And you can place comments like this anywhere you like.
     27 #
     28 # Before running this file, you will need to have installed the thrift compiler
     29 # into /usr/local/bin.
     30 
     31 /**
     32  * The first thing to know about are types. The available types in Thrift are:
     33  *
     34  *  bool        Boolean, one byte
     35  *  i8 (byte)   Signed 8-bit integer
     36  *  i16         Signed 16-bit integer
     37  *  i32         Signed 32-bit integer
     38  *  i64         Signed 64-bit integer
     39  *  double      64-bit floating point value
     40  *  string      String
     41  *  binary      Blob (byte array)
     42  *  map<t1,t2>  Map from one type to another
     43  *  list<t1>    Ordered list of one type
     44  *  set<t1>     Set of unique elements of one type
     45  *
     46  * Did you also notice that Thrift supports C style comments?
     47  */
     48 
     49 // Just in case you were wondering... yes. We support simple C comments too.
     50 
     51 /**
     52  * Thrift files can reference other Thrift files to include common struct
     53  * and service definitions. These are found using the current path, or by
     54  * searching relative to any paths specified with the -I compiler flag.
     55  *
     56  * Included objects are accessed using the name of the .thrift file as a
     57  * prefix. i.e. shared.SharedObject
     58  */
     59 include "shared.thrift"
     60 
     61 /**
     62  * Thrift files can namespace, package, or prefix their output in various
     63  * target languages.
     64  */
     65 namespace cpp tutorial
     66 namespace d tutorial
     67 namespace dart tutorial
     68 namespace java tutorial
     69 namespace php tutorial
     70 namespace perl tutorial
     71 namespace haxe tutorial
     72 
     73 /**
     74  * Thrift lets you do typedefs to get pretty names for your types. Standard
     75  * C style here.
     76  */
     77 typedef i32 MyInteger
     78 
     79 /**
     80  * Thrift also lets you define constants for use across languages. Complex
     81  * types and structs are specified using JSON notation.
     82  */
     83 const i32 INT32CONSTANT = 9853
     84 const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
     85 
     86 /**
     87  * You can define enums, which are just 32 bit integers. Values are optional
     88  * and start at 1 if not supplied, C style again.
     89  */
     90 enum Operation {
     91   ADD = 1,
     92   SUBTRACT = 2,
     93   MULTIPLY = 3,
     94   DIVIDE = 4
     95 }
     96 
     97 /**
     98  * Structs are the basic complex data structures. They are comprised of fields
     99  * which each have an integer identifier, a type, a symbolic name, and an
    100  * optional default value.
    101  *
    102  * Fields can be declared "optional", which ensures they will not be included
    103  * in the serialized output if they aren't set.  Note that this requires some
    104  * manual management in some languages.
    105  */
    106 struct Work {
    107   1: i32 num1 = 0,
    108   2: i32 num2,
    109   3: Operation op,
    110   4: optional string comment,
    111 }
    112 
    113 /**
    114  * Structs can also be exceptions, if they are nasty.
    115  */
    116 exception InvalidOperation {
    117   1: i32 whatOp,
    118   2: string why
    119 }
    120 
    121 /**
    122  * Ahh, now onto the cool part, defining a service. Services just need a name
    123  * and can optionally inherit from another service using the extends keyword.
    124  */
    125 service Calculator extends shared.SharedService {
    126 
    127   /**
    128    * A method definition looks like C code. It has a return type, arguments,
    129    * and optionally a list of exceptions that it may throw. Note that argument
    130    * lists and exception lists are specified using the exact same syntax as
    131    * field lists in struct or exception definitions.
    132    */
    133 
    134    void ping(),
    135 
    136    i32 add(1:i32 num1, 2:i32 num2),
    137 
    138    i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
    139 
    140    /**
    141     * This method has a oneway modifier. That means the client only makes
    142     * a request and does not listen for any response at all. Oneway methods
    143     * must be void.
    144     */
    145    oneway void zip()
    146 
    147 }
    148 
    149 /**
    150  * That just about covers the basics. Take a look in the test/ folder for more
    151  * detailed examples. After you run this file, your generated code shows up
    152  * in folders with names gen-<language>. The generated code isn't too scary
    153  * to look at. It even has pretty indentation.
    154  */
    View Code

    2. 在这两个thrift文件所在的目录下执行java接口文件的定义。

     1 [root@CloudGame thrift-demo]# ll
     2 total 12
     3 -rw-r--r--. 1 root root 1238 Oct  8 14:43 shared.thrift
     4 -rw-r--r--. 1 root root 4906 Oct  8 14:43 tutorial.thrift
     5 [root@CloudGame thrift-demo]# thrift -r --gen java tutorial.thrift 
     6 [WARNING:/home/water/Work/thrift-demo/shared.thrift:27] No generator named 'dart' could be found!
     7 [WARNING:/home/water/Work/thrift-demo/tutorial.thrift:67] No generator named 'dart' could be found!
     8 [root@CloudGame thrift-demo]# 
     9 [root@CloudGame thrift-demo]# thrift -r --gen java shared.thrift 
    10 [WARNING:/home/water/Work/thrift-demo/shared.thrift:27] No generator named 'dart' could be found!

    最后,你会看到一个gen-java的目录出现:

    1 [root@CloudGame thrift-demo]# ll
    2 total 16
    3 drwxr-xr-x. 4 root root 4096 Oct  8 17:52 gen-java
    4 -rw-r--r--. 1 root root 1238 Oct  8 14:43 shared.thrift
    5 -rw-r--r--. 1 root root 4906 Oct  8 14:43 tutorial.thrift
     1 [root@CloudGame thrift-demo]# tree gen-java
     2 gen-java
     3 ├── shared
     4 │   ├── SharedService.java
     5 │   └── SharedStruct.java
     6 └── tutorial
     7     ├── Calculator.java
     8     ├── InvalidOperation.java
     9     ├── Operation.java
    10     ├── tutorialConstants.java
    11     └── Work.java
    12 
    13 2 directories, 7 files

    3. 创建java工程,我这里用的是eclipse下的maven项目,工程创建好后,将gen-java目录下的相关java文件copy到刚才创建出来的maven工程的java目录下。

    最后,将thrift的tutorial链接下,将相关的JavaClient.java以及JavaServer.java文件还有CalculatorHandler.java拷贝到maven工程下面。

    注意,按照官方的tutorial来操作,是没有CalculatorHandler.java这个文件的,需要从thrift-0.9.3 (我的版本是这个,根据自己的版本不同,适当调整)解压目录中的tutorial下面的java目录下找到这个文件,拷贝到公程中相关目录下 (src/main/java/tutorial/)

    4. 在JavaServer.java文件内执行run java application, 结果,出错了!

     1 Starting the simple server...
     2 org.apache.thrift.transport.TTransportException: Error creating the transport
     3     at org.apache.thrift.transport.TSSLTransportFactory.createSSLContext(TSSLTransportFactory.java:214)
     4     at org.apache.thrift.transport.TSSLTransportFactory.getServerSocket(TSSLTransportFactory.java:108)
     5     at server.JavaServer.secure(JavaServer.java:99)
     6     at server.JavaServer$2.run(JavaServer.java:54)
     7     at java.lang.Thread.run(Thread.java:745)
     8 Caused by: java.io.IOException: Could not load file: ../../lib/java/test/.keystore
     9     at org.apache.thrift.transport.TSSLTransportFactory.getStoreAsStream(TSSLTransportFactory.java:255)
    10     at org.apache.thrift.transport.TSSLTransportFactory.createSSLContext(TSSLTransportFactory.java:198)
    11     ... 4 more

    注意,代码中涉及到两个方案,server运行有simple和secure两种实现,simple就不多说了,看看基于SSL的安全解决方案,需要公钥.truststore和私钥.keystore文件。这个嘛,在linux环境下,也比较简单解决,看看keytool,可以搞定。 关于keytool就不多说,google之。

     1 [root@CloudGame java]# keytool 
     2 Key and Certificate Management Tool
     3 
     4 Commands:
     5 
     6  -certreq            Generates a certificate request
     7  -changealias        Changes an entry's alias
     8  -delete             Deletes an entry
     9  -exportcert         Exports certificate
    10  -genkeypair         Generates a key pair
    11  -genseckey          Generates a secret key
    12  -gencert            Generates certificate from a certificate request
    13  -importcert         Imports a certificate or a certificate chain
    14  -importkeystore     Imports one or all entries from another keystore
    15  -keypasswd          Changes the key password of an entry
    16  -list               Lists entries in a keystore
    17  -printcert          Prints the content of a certificate
    18  -printcertreq       Prints the content of a certificate request
    19  -printcrl           Prints the content of a CRL file
    20  -storepasswd        Changes the store password of a keystore
    21 
    22 Use "keytool -command_name -help" for usage of command_name
    23 [root@CloudGame java]# keytool -genkeypair -alias certificatekey -keyalg RSA -validity 36500 -keystore .keystore
    24 Enter keystore password:  
    25 Re-enter new password: 
    26 What is your first and last name?
    27   [Unknown]:  shihu cheng
    28 What is the name of your organizational unit?
    29   [Unknown]:  tk
    30 What is the name of your organization?
    31   [Unknown]:  tk
    32 What is the name of your City or Locality?
    33   [Unknown]:  wuhan
    34 What is the name of your State or Province?
    35   [Unknown]:  hubei
    36 What is the two-letter country code for this unit?
    37   [Unknown]:  86
    38 Is CN=shihu cheng, OU=tk, O=tk, L=wuhan, ST=hubei, C=86 correct?
    39   [no]:  y
    40 
    41 Enter key password for <certificatekey>
    42     (RETURN if same as keystore password):  
    43 Re-enter new password: 

    这里,密码一定要记得哟,是私钥的密码。在server运行的时候,需要这个信息。

    上面是私钥的生成,接下来看看证书的生成过程。

    1 [root@CloudGame java]# keytool -export -alias certificatekey -keystore .keystore -rfc -file server.cer
    2 Enter keystore password:  
    3 Certificate stored in file <server.cer>

    最后,利用证书生成公钥。

     1 [root@CloudGame java]# keytool -import -alias certificatekey -file server.cer -keystore .truststore
     2 Enter keystore password:  
     3 Re-enter new password: 
     4 Owner: CN=shihu cheng, OU=tk, O=tk, L=wuhan, ST=hubei, C=86
     5 Issuer: CN=shihu cheng, OU=tk, O=tk, L=wuhan, ST=hubei, C=86
     6 Serial number: 7b031382
     7 Valid from: Sat Oct 08 16:39:51 HKT 2016 until: Mon Sep 14 16:39:51 HKT 2116
     8 Certificate fingerprints:
     9      MD5:  55:52:F8:BF:47:60:8C:3D:B1:46:10:A7:00:3F:B0:EC
    10      SHA1: D8:36:EE:48:07:A0:58:40:60:D8:24:7D:7E:61:C5:9B:95:70:B1:89
    11      SHA256: F5:9B:DE:91:2D:3B:64:7E:B8:0B:3A:1C:91:A2:55:96:D4:79:B4:D8:C4:67:AF:84:3B:80:41:49:55:89:26:E1
    12      Signature algorithm name: SHA256withRSA
    13      Version: 3
    14 
    15 Extensions: 
    16 
    17 #1: ObjectId: 2.5.29.14 Criticality=false
    18 SubjectKeyIdentifier [
    19 KeyIdentifier [
    20 0000: 37 61 64 8D F8 72 1F 2D   DD 2C 04 48 42 03 64 E5  7ad..r.-.,.HB.d.
    21 0010: 4E DC EA 79                                        N..y
    22 ]
    23 ]
    24 
    25 Trust this certificate? [no]:  y
    26 Certificate was added to keystore

    将上面生成的私钥.keystore拷贝到maven工程目录的server目录下,将公钥.truststore拷贝到maven工程的client目录下,修改JavaClient.java以及JavaServer.java相关的代码如下:

      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the
      7  * "License"); you may not use this file except in compliance
      8  * with the License. You may obtain a copy of the License at
      9  *
     10  *   http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing,
     13  * software distributed under the License is distributed on an
     14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15  * KIND, either express or implied. See the License for the
     16  * specific language governing permissions and limitations
     17  * under the License.
     18  */
     19 
     20 package client;
     21 
     22 // Generated code
     23 import tutorial.*;
     24 import shared.*;
     25 
     26 import org.apache.thrift.TException;
     27 import org.apache.thrift.transport.TSSLTransportFactory;
     28 import org.apache.thrift.transport.TTransport;
     29 import org.apache.thrift.transport.TSocket;
     30 import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
     31 import org.apache.thrift.protocol.TBinaryProtocol;
     32 import org.apache.thrift.protocol.TProtocol;
     33 
     34 public class JavaClient {
     35   public static void main(String [] args) {
     36 
     37     if (args.length != 1) {
     38       System.out.println("Please enter 'simple' or 'secure'");
     39       System.exit(0);
     40     }
     41 
     42     try {
     43       TTransport transport;
     44       if (args[0].contains("simple")) {
     45         transport = new TSocket("localhost", 9090);
     46         transport.open();
     47       }
     48       else {
     49         /*
     50          * Similar to the server, you can use the parameters to setup client parameters or
     51          * use the default settings. On the client side, you will need a TrustStore which
     52          * contains the trusted certificate along with the public key. 
     53          * For this example it's a self-signed cert. 
     54          */
     55         TSSLTransportParameters params = new TSSLTransportParameters();
     56         params.setTrustStore("./src/main/java/client/.truststore", "shihuc", "SunX509", "JKS");
     57         /*
     58          * Get a client transport instead of a server transport. The connection is opened on
     59          * invocation of the factory method, no need to specifically call open()
     60          */
     61         transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params);
     62       }
     63 
     64       TProtocol protocol = new  TBinaryProtocol(transport);
     65       Calculator.Client client = new Calculator.Client(protocol);
     66 
     67       perform(client);
     68 
     69       transport.close();
     70     } catch (TException x) {
     71       x.printStackTrace();
     72     } 
     73   }
     74 
     75   private static void perform(Calculator.Client client) throws TException
     76   {
     77     client.ping();
     78     System.out.println("ping()");
     79 
     80     int sum = client.add(1,1);
     81     System.out.println("1+1=" + sum);
     82 
     83     Work work = new Work();
     84 
     85     work.op = Operation.DIVIDE;
     86     work.num1 = 1;
     87     work.num2 = 0;
     88     try {
     89       int quotient = client.calculate(1, work);
     90       System.out.println("Whoa we can divide by 0");
     91     } catch (InvalidOperation io) {
     92       System.out.println("Invalid operation: " + io.why);
     93     }
     94 
     95     work.op = Operation.SUBTRACT;
     96     work.num1 = 15;
     97     work.num2 = 10;
     98     try {
     99       int diff = client.calculate(1, work);
    100       System.out.println("15-10=" + diff);
    101     } catch (InvalidOperation io) {
    102       System.out.println("Invalid operation: " + io.why);
    103     }
    104 
    105     SharedStruct log = client.getStruct(1);
    106     System.out.println("Check log: " + log.value);
    107   }
    108 }
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the
      7  * "License"); you may not use this file except in compliance
      8  * with the License. You may obtain a copy of the License at
      9  *
     10  *   http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing,
     13  * software distributed under the License is distributed on an
     14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15  * KIND, either express or implied. See the License for the
     16  * specific language governing permissions and limitations
     17  * under the License.
     18  */
     19 
     20 package server;
     21 import org.apache.thrift.server.TServer;
     22 import org.apache.thrift.server.TServer.Args;
     23 import org.apache.thrift.server.TSimpleServer;
     24 import org.apache.thrift.server.TThreadPoolServer;
     25 import org.apache.thrift.transport.TSSLTransportFactory;
     26 import org.apache.thrift.transport.TServerSocket;
     27 import org.apache.thrift.transport.TServerTransport;
     28 import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
     29 
     30 // Generated code
     31 import tutorial.*;
     32 import shared.*;
     33 
     34 import java.util.HashMap;
     35 
     36 public class JavaServer {
     37 
     38   public static CalculatorHandler handler;
     39 
     40   public static Calculator.Processor processor;
     41 
     42   public static void main(String [] args) {
     43     try {
     44       handler = new CalculatorHandler();
     45       processor = new Calculator.Processor(handler);
     46 
     47       Runnable simple = new Runnable() {
     48         public void run() {
     49           simple(processor);
     50         }
     51       };      
     52       Runnable secure = new Runnable() {
     53         public void run() {
     54           secure(processor);
     55         }
     56       };
     57 
     58       new Thread(simple).start();
     59       new Thread(secure).start();
     60     } catch (Exception x) {
     61       x.printStackTrace();
     62     }
     63   }
     64 
     65   public static void simple(Calculator.Processor processor) {
     66     try {
     67       TServerTransport serverTransport = new TServerSocket(9090);
     68       TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
     69 
     70       // Use this for a multithreaded server
     71       // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
     72 
     73       System.out.println("Starting the simple server...");
     74       server.serve();
     75     } catch (Exception e) {
     76       e.printStackTrace();
     77     }
     78   }
     79 
     80   public static void secure(Calculator.Processor processor) {
     81     try {
     82       /*
     83        * Use TSSLTransportParameters to setup the required SSL parameters. In this example
     84        * we are setting the keystore and the keystore password. Other things like algorithms,
     85        * cipher suites, client auth etc can be set. 
     86        */
     87       TSSLTransportParameters params = new TSSLTransportParameters();
     88       // The Keystore contains the private key
     89       params.setKeyStore("./src/main/java/server/.keystore", "shihuc", null, null);
     90 
     91       /*
     92        * Use any of the TSSLTransportFactory to get a server transport with the appropriate
     93        * SSL configuration. You can use the default settings if properties are set in the command line.
     94        * Ex: -Djavax.net.ssl.keyStore=.keystore and -Djavax.net.ssl.keyStorePassword=thrift
     95        * 
     96        * Note: You need not explicitly call open(). The underlying server socket is bound on return
     97        * from the factory class. 
     98        */
     99       TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params);
    100       TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
    101 
    102       // Use this for a multi threaded server
    103       // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
    104 
    105       System.out.println("Starting the secure server...");
    106       server.serve();
    107     } catch (Exception e) {
    108       e.printStackTrace();
    109     }
    110   }
    111 }

    最后,再次运行JavaServer.java,得到下面的信息就对了!

    1 Starting the simple server...
    2 Starting the secure server...

    然后,配置eclipse的运行参数arguments为secure,运行JavaClient.java,得到下面的信息:

    1 ping()
    2 1+1=2
    3 Invalid operation: Cannot divide by 0
    4 15-10=5
    5 Check log: 5

    到此,一个简单的thrift java语言的RPC程序就算是跑通了。

    这里演示用的maven工程代码,可以在我的github上下载,作为参考,学习交流。

  • 相关阅读:
    数据库排名函数(Rank)
    请求支付报表的测试
    DateTime详细资料转载
    sqlserver2005的安装问题
    Hdu 1398 Square Coins
    HDU 1709 The Balance
    POJ 1423 Big Number
    hdu 1106 排序
    HDU 1028 Ignatius and the Princess III
    并查集Is It A Tree?hdu 1325
  • 原文地址:https://www.cnblogs.com/shihuc/p/5941733.html
Copyright © 2011-2022 走看看