菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
430
0

thrift demo

原创
05/13 14:22
阅读数 47552

基于上一篇博客,安装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上下载,作为参考,学习交流。

 

发表评论

0/200
430 点赞
0 评论
收藏