- If one function in server need 10 seconds to finish , and client one time send 100 request , How to know how many request is pending ?
For all the girls I loved
bool A boolean value, true or false
byte A signed byte
i16 A 16-bit signed integer
i32 A 32-bit signed integer
i64 A 64-bit signed integer
double A 64-bit floating point number
string An encoding-agnostic text or binary string
A struct is essentially equivalent to a class in object oriented
programming languages. A struct has a set of strongly typed
fields, each with a unique name identifier. The basic syntax for
defining a Thrift struct looks very similar to a C struct definition.
Fields may be annotated with an integer field identifier (unique to
the scope of that struct) and optional default values. Field identifiers
will be automatically assigned if omitted, though they are strongly
encouraged for versioning reasons discussed later.
Example of struct
1 2 3 4 5 6 |
struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } |
1 2 3 4 5 6 7 |
struct Example { 1:i32 number=10, 2:i64 bigNumber, 3:double decimals, 4:string name="thrifty" } |
Services are defined using Thrift types. Definition of a service is
semantically equivalent to defining an interface (or a pure virtual
abstract class) in object oriented programming. The Thrift compiler
generates fully functional client and server stubs that implement the
interface. Services are defined as follows:
1 2 3 4 5 |
service <name> { <returntype> <name>(<arguments>) [throws (<exceptions>)] ... } |
An example is :
1 2 3 4 5 |
service StringCache { void set(1:i32 key, 2:string value), string get(1:i32 key) throws (1:KeyNotFound knf), void delete(1:i32 key) } |
Note : an async modifier keyword may be added to a void function, which will generate code that does not wait for a response from the server.
Thrift services require basic multithreading to handle simultaneous
requests from multiple clients
**** Important
Now I will create a RouteServer which supply a “QueryRoute” function , client send Anumber and Bnumber as parameter , server will reply a struct include 2 int and 1 string , how to write this service ?
1 2 3 4 5 |
struct Ret { 1: i32 num1 = 0, 2: i32 num2, 3: string routeID, } |
1 2 3 |
service RouteServer { Ret QueryRoute(1:string Anumber, 2:string Bnumber) } |
Full thrift file is : name is “RouteServer.thrift”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
namespace netcore tutorial # only gen cSharp server and client exception InvalidOperation { 1: i32 whatOp, 2: string why } struct Ret { 1: i32 num1 = 0, 2: i32 num2, 3: string routeID, } service RouteServer { Ret QueryRoute(1:string Anumber, 2:string Bnumber) } |
goto folder : /home/liuyang/thrift-0.11.0/tutorial
run command : rm -r gen-csharp , delete existing folder
then run command : thrift -r –gen csharp RouteServer.thrift
Then goto /home/liuyang/thrift-0.11.0/tutorial/gen-csharp , copy “RouteServer.cs” and “InvalidOperation.cs” and “Ret.cs” to windows machine console application , add to project .
For server side “Program.cs” ,change it to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Thrift.Server; using Thrift.Transport; namespace RouteService { public class RouteServerHandler : RouteServer.Iface { Dictionary<int, SharedStruct> log; public RouteServerHandler() { log = new Dictionary<int, SharedStruct>(); } public SharedStruct getStruct(int key) { //Console.WriteLine("getStruct({0})", key); return log[key]; } public Ret QueryRoute(string anumber, string bnumber) { Ret r1 = new Ret(); r1.Num1 = 1; r1.Num2 = 2; r1.RouteID = "MaxisRoute"; return r1; } } class Program { static void Main(string[] args) { try { RouteServerHandler handler = new RouteServerHandler(); RouteServer.Processor processor = new RouteServer.Processor(handler); TServerTransport serverTransport = new TServerSocket(9090); //TServer server = new TSimpleServer(processor, serverTransport); TServer server = new TThreadPoolServer(processor, serverTransport); // Use this for a multithreaded server // server = new TThreadPoolServer(processor, serverTransport); Console.WriteLine("Starting the server..."); server.Serve(); } catch (Exception x) { Console.WriteLine(x.StackTrace); } Console.WriteLine("done."); Console.ReadLine(); } } } |
For client “Program.cs” ,change it to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Thrift; using Thrift.Protocol; using Thrift.Server; using Thrift.Transport; namespace RouteClient { class Program { static void Main(string[] args) { try { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); RouteServer.Client client = new RouteServer.Client(protocol); transport.Open(); try { string s1 = ""; string s2 = ""; Ret r2 = client.QueryRoute(s1, s2); s1 = ""; } finally { transport.Close(); } } catch (TApplicationException x) { Console.WriteLine(x.StackTrace); } } } } |
Now client can call server function and get reply .
Setting up a Thrift Server
https://medium.com/@saipeddy/setting-up-a-thrift-server-4eb0c55c11f0
wget http://mirror.bit.edu.cn/apache/thrift/0.11.0/thrift-0.11.0.tar.gz
https://thrift.apache.org/docs/install/debian
Now will install them one by one
a) install mono complete by https://gist.github.com/carolynvs/4520736f6017ca252a44
1 2 3 4 5 6 7 8 9 10 |
wget http://download.mono-project.com/repo/xamarin.gpg sudo apt-key add xamarin.gpg echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee --append /etc/apt/sources.list.d/mono-xamarin.list sudo apt-get update sudo apt-get install mono-complete <del>sudo certmgr -ssl -m https://go.microsoft.com sudo certmgr -ssl -m https://nugetgallery.blob.core.windows.net sudo certmgr -ssl -m https://nuget.org mozroots --import --sync</del> |
only exec first 5 steps
b) install nunit by this command : sudo apt-get install nunit nunit-console
from https://zxtech.wordpress.com/2015/01/05/install-nunit-on-ubuntu/
Now all the pre-requirement are installed .
From https://thrift.apache.org/docs/BuildingFromSource
goto /home/liuyang/thrift-0.11.0/
run command one by one :
1 |
./bootstrap.sh |
1 |
./configure |
1 |
make |
1 |
make check <span style="color: #0000ff;"> this step fail </span> |
1 |
sh test/test.sh <span style="color: #0000ff;">this step not exec</span> |
1 |
make install <span style="color: #0000ff;">***** very important , MUST install </span> |
A cSharp project which use thrift should add reference to “Thrift.dll”
goto folder : /home/liuyang/thrift-0.11.0/tutorial
run command : rm -r csharp , delete existing csharp folder
then run command : thrift -r –gen csharp tutorial.thrift
there will be a new folder named “gen-csharp” , and here is the file will be used as server and client ,But no .sln file .
Thrift will gen both server and client side code , Now try to make a server side project , it need these files :
1 2 3 4 5 6 |
Calculator.cs InvalidOperation.cs Operation.cs SharedService.cs SharedStruct.cs Work.cs |
then change server side ‘s Program.cs to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System; using System.Collections.Generic; using Thrift.Server; using Thrift.Transport; namespace thriftServer { public class CalculatorHandler : Calculator.Iface { Dictionary<int, SharedStruct> log; public CalculatorHandler() { log = new Dictionary<int, SharedStruct>(); } public void ping() { //Console.WriteLine("ping()"); } public int add(int n1, int n2) { //Console.WriteLine("add({0},{1})", n1, n2); return n1 + n2; } public int calculate(int logid, Work work) { //Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.Op, work.Num1, work.Num2); int val = 0; switch (work.Op) { case Operation.ADD: val = work.Num1 + work.Num2; break; case Operation.SUBTRACT: val = work.Num1 - work.Num2; break; case Operation.MULTIPLY: val = work.Num1 * work.Num2; break; case Operation.DIVIDE: if (work.Num2 == 0) { InvalidOperation io = new InvalidOperation(); io.WhatOp = (int)work.Op; io.Why = "Cannot divide by 0"; throw io; } val = work.Num1 / work.Num2; break; default: { InvalidOperation io = new InvalidOperation(); io.WhatOp = (int)work.Op; io.Why = "Unknown operation"; throw io; } } SharedStruct entry = new SharedStruct(); entry.Key = logid; entry.Value = val.ToString(); log[logid] = entry; return val; } public SharedStruct getStruct(int key) { //Console.WriteLine("getStruct({0})", key); return log[key]; } public void zip() { //Console.WriteLine("zip()"); } } public class Program { public static void Main() { try { CalculatorHandler handler = new CalculatorHandler(); Calculator.Processor processor = new Calculator.Processor(handler); TServerTransport serverTransport = new TServerSocket(9090); //TServer server = new TSimpleServer(processor, serverTransport); TServer server = new TThreadPoolServer(processor, serverTransport); // Use this for a multithreaded server // server = new TThreadPoolServer(processor, serverTransport); Console.WriteLine("Starting the server..."); server.Serve(); } catch (Exception x) { Console.WriteLine(x.StackTrace); } Console.WriteLine("done."); Console.ReadLine(); } } } |
For client side , need same cs files with server , only it ‘s Program.cs file content is :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
using System; using Thrift; using Thrift.Protocol; using Thrift.Server; using Thrift.Transport; using log4net; using System.Threading; namespace thriftClient { public class Program { //private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public static void Main() { try { //Logger.Info("Hello logging world!"); Logger.Info(DateTime.Now.ToString()); 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()"); /* original gen code 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); */ /* not use thread total use 1 min for (int i = 1; i < 10000; i++) { Work work = new Work(); work.Op = Operation.MULTIPLY; work.Num1 = i; work.Num2 = i; int sum = client.calculate(i, work); Logger.Info(i.ToString() + @"'s multiply result is : " + sum.ToString()); } Logger.Info(DateTime.Now.ToString()); */ Thread oThreadone = new Thread(Work1); Thread oThreadtwo = new Thread(Work2); Thread oThreadthree = new Thread(Work3); Thread oThreadfour = new Thread(Work4); Thread oThreadfive = new Thread(Work5); oThreadone.Start(); oThreadtwo.Start(); oThreadthree.Start(); oThreadfour.Start(); oThreadfive.Start(); } finally { transport.Close(); } } catch (TApplicationException x) { Console.WriteLine(x.StackTrace); } } //end of main static void Work1() { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); transport.Open(); Work work = new Work(); for (int i = 1; i < 2000; i++) { //Work work = new Work(); work.Op = Operation.MULTIPLY; work.Num1 = i; work.Num2 = i; int sum = client.calculate(i, work); //Logger.Info(i.ToString() + @"'s multiply result is : " + sum.ToString()); } Logger.Info(DateTime.Now.ToString()); } static void Work2() { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); transport.Open(); Work work = new Work(); for (int i = 2000; i < 4000; i++) { //Work work = new Work(); work.Op = Operation.MULTIPLY; work.Num1 = i; work.Num2 = i; int sum = client.calculate(i, work); // Logger.Info(i.ToString() + @"'s multiply result is : " + sum.ToString()); } Logger.Info(DateTime.Now.ToString()); } static void Work3() { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); transport.Open(); Work work = new Work(); for (int i = 4000; i < 6000; i++) { //Work work = new Work(); work.Op = Operation.MULTIPLY; work.Num1 = i; work.Num2 = i; int sum = client.calculate(i, work); //Logger.Info(i.ToString() + @"'s multiply result is : " + sum.ToString()); } Logger.Info(DateTime.Now.ToString()); } static void Work4() { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); transport.Open(); Work work = new Work(); for (int i = 6000; i < 8000; i++) { //Work work = new Work(); work.Op = Operation.MULTIPLY; work.Num1 = i; work.Num2 = i; int sum = client.calculate(i, work); // Logger.Info(i.ToString() + @"'s multiply result is : " + sum.ToString()); } Logger.Info(DateTime.Now.ToString()); } static void Work5() { TTransport transport = new TSocket("localhost", 9090); TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); transport.Open(); Work work = new Work(); for (int i = 8000; i < 10000; i++) { //Work work = new Work(); work.Op = Operation.MULTIPLY; work.Num1 = i; work.Num2 = i; int sum = client.calculate(i, work); //Logger.Info(i.ToString() + @"'s multiply result is : " + sum.ToString()); } Logger.Info(DateTime.Now.ToString()); } } } |
Q&A
Thrift script analyze
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ # Thrift Tutorial # Mark Slee (mcslee@facebook.com) # # This file aims to teach you how to use Thrift, in a .thrift file. Neato. The # first thing to notice is that .thrift files support standard shell comments. # This lets you make your thrift file executable and include your Thrift build # step on the top line. And you can place comments like this anywhere you like. # # Before running this file, you will need to have installed the thrift compiler # into /usr/local/bin. /** * The first thing to know about are types. The available types in Thrift are: * * bool Boolean, one byte * i8 (byte) Signed 8-bit integer * i16 Signed 16-bit integer * i32 Signed 32-bit integer * i64 Signed 64-bit integer * double 64-bit floating point value * string String * binary Blob (byte array) * map<t1,t2> Map from one type to another * list<t1> Ordered list of one type * set<t1> Set of unique elements of one type * * Did you also notice that Thrift supports C style comments? */ // Just in case you were wondering... yes. We support simple C comments too. /** * Thrift files can reference other Thrift files to include common struct * and service definitions. These are found using the current path, or by * searching relative to any paths specified with the -I compiler flag. * * Included objects are accessed using the name of the .thrift file as a * prefix. i.e. shared.SharedObject */ include "shared.thrift" /** * Thrift files can namespace, package, or prefix their output in various * target languages. */ namespace cpp tutorial namespace d tutorial namespace dart tutorial namespace java tutorial namespace php tutorial namespace perl tutorial namespace haxe tutorial namespace netcore tutorial /** * Thrift lets you do typedefs to get pretty names for your types. Standard * C style here. */ typedef i32 MyInteger /** * Thrift also lets you define constants for use across languages. Complex * types and structs are specified using JSON notation. */ const i32 INT32CONSTANT = 9853 const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} /** * You can define enums, which are just 32 bit integers. Values are optional * and start at 1 if not supplied, C style again. */ enum Operation { ADD = 1, SUBTRACT = 2, MULTIPLY = 3, DIVIDE = 4 } /** * Structs are the basic complex data structures. They are comprised of fields * which each have an integer identifier, a type, a symbolic name, and an * optional default value. * * Fields can be declared "optional", which ensures they will not be included * in the serialized output if they aren't set. Note that this requires some * manual management in some languages. */ struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } /** * Structs can also be exceptions, if they are nasty. */ exception InvalidOperation { 1: i32 whatOp, 2: string why } /** * Ahh, now onto the cool part, defining a service. Services just need a name * and can optionally inherit from another service using the extends keyword. */ service Calculator extends shared.SharedService { /** * A method definition looks like C code. It has a return type, arguments, * and optionally a list of exceptions that it may throw. Note that argument * lists and exception lists are specified using the exact same syntax as * field lists in struct or exception definitions. */ void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), /** * This method has a oneway modifier. That means the client only makes * a request and does not listen for any response at all. Oneway methods * must be void. */ oneway void zip() } /** * That just about covers the basics. Take a look in the test/ folder for more * detailed examples. After you run this file, your generated code shows up * in folders with names gen-<language>. The generated code isn't too scary * to look at. It even has pretty indentation. */ |