thrift

thrift官网

基于thrift实现的匹配机制

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。

我的理解就是实现服务器之间交互的框架,微服务。

thrift接口框架

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
/*
开发基本就是那这个框架改改
*/
/*
* 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 cl tutorial
namespace cpp tutorial
namespace d tutorial
namespace dart tutorial
namespace java tutorial
namespace php tutorial
namespace perl tutorial
namespace haxe tutorial
namespace netstd 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.
*/

C++

1
thrift -r --gen cpp tutorial.thrift //生成tutorial.thrift和shared.thrift文件

Client(客户端)

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
#include <iostream>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#include "../gen-cpp/Calculator.h"

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace tutorial;
using namespace shared;

int main() {
std::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
CalculatorClient client(protocol);

try {
transport->open();

client.ping();
cout << "ping()" << endl;

cout << "1 + 1 = " << client.add(1, 1) << endl;

Work work;
work.op = Operation::DIVIDE;
work.num1 = 1;
work.num2 = 0;

try {
client.calculate(1, work);
cout << "Whoa? We can divide by zero!" << endl;
} catch (InvalidOperation& io) {
cout << "InvalidOperation: " << io.why << endl;
// or using generated operator<<: cout << io << endl;
// or by using std::exception native method what(): cout << io.what() << endl;
}

work.op = Operation::SUBTRACT;
work.num1 = 15;
work.num2 = 10;
int32_t diff = client.calculate(1, work);
cout << "15 - 10 = " << diff << endl;

// Note that C++ uses return by reference for complex types to avoid
// costly copy construction
SharedStruct ss;
client.getStruct(ss, 1);
cout << "Received log: " << ss << endl;

transport->close();
} catch (TException& tx) {
cout << "ERROR: " << tx.what() << endl;
}
}

Server(服务器)

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
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/TToString.h>

#include <iostream>
#include <stdexcept>
#include <sstream>

#include "../gen-cpp/Calculator.h"

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::concurrency;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;

using namespace tutorial;
using namespace shared;

class CalculatorHandler : public CalculatorIf {
public:
CalculatorHandler() = default;

void ping() override { cout << "ping()" << endl; }

int32_t add(const int32_t n1, const int32_t n2) override {
cout << "add(" << n1 << ", " << n2 << ")" << endl;
return n1 + n2;
}

int32_t calculate(const int32_t logid, const Work& work) override {
cout << "calculate(" << logid << ", " << work << ")" << endl;
int32_t val;

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;
io.whatOp = work.op;
io.why = "Cannot divide by 0";
throw io;
}
val = work.num1 / work.num2;
break;
default:
InvalidOperation io;
io.whatOp = work.op;
io.why = "Invalid Operation";
throw io;
}

SharedStruct ss;
ss.key = logid;
ss.value = to_string(val);

log[logid] = ss;

return val;
}

void getStruct(SharedStruct& ret, const int32_t logid) override {
cout << "getStruct(" << logid << ")" << endl;
ret = log[logid];
}

void zip() override { cout << "zip()" << endl; }

protected:
map<int32_t, SharedStruct> log;
};

/*
CalculatorIfFactory is code generated.
CalculatorCloneFactory is useful for getting access to the server side of the
transport. It is also useful for making per-connection state. Without this
CloneFactory, all connections will end up sharing the same handler instance.
*/
class CalculatorCloneFactory : virtual public CalculatorIfFactory {
public:
~CalculatorCloneFactory() override = default;
CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) override
{
std::shared_ptr<TSocket> sock = std::dynamic_pointer_cast<TSocket>(connInfo.transport);
cout << "Incoming connection\n";
cout << "\tSocketInfo: " << sock->getSocketInfo() << "\n";
cout << "\tPeerHost: " << sock->getPeerHost() << "\n";
cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
cout << "\tPeerPort: " << sock->getPeerPort() << "\n";
return new CalculatorHandler;
}
void releaseHandler( ::shared::SharedServiceIf* handler) override {
delete handler;
}
};

int main() {
TThreadedServer server(
std::make_shared<CalculatorProcessorFactory>(std::make_shared<CalculatorCloneFactory>()),
std::make_shared<TServerSocket>(9090), //port
std::make_shared<TBufferedTransportFactory>(),
std::make_shared<TBinaryProtocolFactory>());

/*
// if you don't need per-connection state, do the following instead
TThreadedServer server(
std::make_shared<CalculatorProcessor>(std::make_shared<CalculatorHandler>()),
std::make_shared<TServerSocket>(9090), //port
std::make_shared<TBufferedTransportFactory>(),
std::make_shared<TBinaryProtocolFactory>());
*/

/**
* Here are some alternate server types...

// This server only allows one connection at a time, but spawns no threads
TSimpleServer server(

Python

1
thrift -r --gen py tutorial.thrift //生成tutorial.thrift和shared.thrift文件

Client(客户端)

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
import sys
import glob
sys.path.append('gen-py')
sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])

from tutorial import Calculator
from tutorial.ttypes import InvalidOperation, Operation, Work

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol


def main():
# Make socket
transport = TSocket.TSocket('localhost', 9090)

# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)

# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)

# Create a client to use the protocol encoder
client = Calculator.Client(protocol)

# Connect!
transport.open()

client.ping()
print('ping()')

sum_ = client.add(1, 1)
print('1+1=%d' % sum_)

work = Work()

work.op = Operation.DIVIDE
work.num1 = 1
work.num2 = 0

try:
quotient = client.calculate(1, work)
print('Whoa? You know how to divide by zero?')
print('FYI the answer is %d' % quotient)
except InvalidOperation as e:
print('InvalidOperation: %r' % e)

work.op = Operation.SUBTRACT
work.num1 = 15
work.num2 = 10

diff = client.calculate(1, work)
print('15-10=%d' % diff)

log = client.getStruct(1)
print('Check log: %s' % log.value)

# Close!
transport.close()

Server(服务器)

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
import glob
import sys
sys.path.append('gen-py')
sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])

from tutorial import Calculator
from tutorial.ttypes import InvalidOperation, Operation

from shared.ttypes import SharedStruct

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer


class CalculatorHandler:
def __init__(self):
self.log = {}

def ping(self):
print('ping()')

def add(self, n1, n2):
print('add(%d,%d)' % (n1, n2))
return n1 + n2

def calculate(self, logid, work):
print('calculate(%d, %r)' % (logid, work))

if work.op == Operation.ADD:
val = work.num1 + work.num2
elif work.op == Operation.SUBTRACT:
val = work.num1 - work.num2
elif work.op == Operation.MULTIPLY:
val = work.num1 * work.num2
elif work.op == Operation.DIVIDE:
if work.num2 == 0:
raise InvalidOperation(work.op, 'Cannot divide by 0')
val = work.num1 / work.num2
else:
raise InvalidOperation(work.op, 'Invalid operation')

log = SharedStruct()
log.key = logid
log.value = '%d' % (val)
self.log[logid] = log

return val

def getStruct(self, key):
print('getStruct(%d)' % (key))
return self.log[key]

def zip(self):
print('zip()')


if __name__ == '__main__':
handler = CalculatorHandler()
processor = Calculator.Processor(handler)
transport = TSocket.TServerSocket(host='127.0.0.1', port=9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()

server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

# You could do one of these for a multithreaded server
# server = TServer.TThreadedServer(
# processor, transport, tfactory, pfactory)
# server = TServer.TThreadPoolServer(
# processor, transport, tfactory, pfactory)

print('Starting the server...')
server.serve()
print('done.')

Java

1
thrift -r --gen java tutorial.thrift //生成tutorial.thrift和shared.thrift文件

Clien(客户端)

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
/*
* 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.
*/

// Generated code
import tutorial.*;
import shared.*;

import org.apache.thrift.TException;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;

public class JavaClient {
public static void main(String [] args) {

if (args.length != 1) {
System.out.println("Please enter 'simple' or 'secure'");
System.exit(0);
}

try {
TTransport transport;
if (args[0].contains("simple")) {
transport = new TSocket("localhost", 9090);
transport.open();
}
else {
/*
* Similar to the server, you can use the parameters to setup client parameters or
* use the default settings. On the client side, you will need a TrustStore which
* contains the trusted certificate along with the public key.
* For this example it's a self-signed cert.
*/
TSSLTransportParameters params = new TSSLTransportParameters();
params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS");
/*
* Get a client transport instead of a server transport. The connection is opened on
* invocation of the factory method, no need to specifically call open()
*/
transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params);
}

TProtocol protocol = new TBinaryProtocol(transport);
Calculator.Client client = new Calculator.Client(protocol);

perform(client);

transport.close();
} catch (TException x) {
x.printStackTrace();
}
}

private static void perform(Calculator.Client client) throws TException
{
client.ping();
System.out.println("ping()");

int sum = client.add(1,1);
System.out.println("1+1=" + sum);

Work work = new Work();

work.op = Operation.DIVIDE;
work.num1 = 1;
work.num2 = 0;
try {
int quotient = client.calculate(1, work);
System.out.println("Whoa we can divide by 0");
} catch (InvalidOperation io) {
System.out.println("Invalid operation: " + io.why);
}

work.op = Operation.SUBTRACT;
work.num1 = 15;
work.num2 = 10;
try {
int diff = client.calculate(1, work);
System.out.println("15-10=" + diff);
} catch (InvalidOperation io) {
System.out.println("Invalid operation: " + io.why);
}

SharedStruct log = client.getStruct(1);
System.out.println("Check log: " + log.value);
}
}

CalculatorHandler(计算机处理程序)

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
/*
* 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.
*/

import org.apache.thrift.TException;

// Generated code
import tutorial.*;
import shared.*;

import java.util.HashMap;

public class CalculatorHandler implements Calculator.Iface {

private HashMap<Integer,SharedStruct> log;

public CalculatorHandler() {
log = new HashMap<Integer, SharedStruct>();
}

public void ping() {
System.out.println("ping()");
}

public int add(int n1, int n2) {
System.out.println("add(" + n1 + "," + n2 + ")");
return n1 + n2;
}

public int calculate(int logid, Work work) throws InvalidOperation {
System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})");
int val = 0;
switch (work.op) {
case ADD:
val = work.num1 + work.num2;
break;
case SUBTRACT:
val = work.num1 - work.num2;
break;
case MULTIPLY:
val = work.num1 * work.num2;
break;
case DIVIDE:
if (work.num2 == 0) {
InvalidOperation io = new InvalidOperation();
io.whatOp = work.op.getValue();
io.why = "Cannot divide by 0";
throw io;
}
val = work.num1 / work.num2;
break;
default:
InvalidOperation io = new InvalidOperation();
io.whatOp = work.op.getValue();
io.why = "Unknown operation";
throw io;
}

SharedStruct entry = new SharedStruct();
entry.key = logid;
entry.value = Integer.toString(val);
log.put(logid, entry);

return val;
}

public SharedStruct getStruct(int key) {
System.out.println("getStruct(" + key + ")");
return log.get(key);
}

public void zip() {
System.out.println("zip()");
}

}

Server(服务器)

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
/*
* 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.
*/

import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;

// Generated code
import tutorial.*;
import shared.*;

import java.util.HashMap;

public class JavaServer {

public static CalculatorHandler handler;

public static Calculator.Processor processor;

public static void main(String [] args) {
try {
handler = new CalculatorHandler();
processor = new Calculator.Processor(handler);

Runnable simple = new Runnable() {
public void run() {
simple(processor);
}
};
Runnable secure = new Runnable() {
public void run() {
secure(processor);
}
};

new Thread(simple).start();
new Thread(secure).start();
} catch (Exception x) {
x.printStackTrace();
}
}

public static void simple(Calculator.Processor processor) {
try {
TServerTransport serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

// Use this for a multithreaded server
// TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));

System.out.println("Starting the simple server...");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}

public static void secure(Calculator.Processor processor) {
try {
/*
* Use TSSLTransportParameters to setup the required SSL parameters. In this example
* we are setting the keystore and the keystore password. Other things like algorithms,
* cipher suites, client auth etc can be set.
*/
TSSLTransportParameters params = new TSSLTransportParameters();
// The Keystore contains the private key
params.setKeyStore("../../lib/java/test/.keystore", "thrift", null, null);

/*
* Use any of the TSSLTransportFactory to get a server transport with the appropriate
* SSL configuration. You can use the default settings if properties are set in the command line.
* Ex: -Djavax.net.ssl.keyStore=.keystore and -Djavax.net.ssl.keyStorePassword=thrift
*
* Note: You need not explicitly call open(). The underlying server socket is bound on return
* from the factory class.
*/
TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params);
TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));

// Use this for a multi threaded server
// TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));

System.out.println("Starting the secure server...");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Go

1
thrift -r --gen go tutorial.thrift//生成tutorial.thrift和shared.thrift文件

Client(客户端)

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
import (
"context"
"fmt"

"github.com/apache/thrift/lib/go/thrift"
"github.com/apache/thrift/tutorial/go/gen-go/tutorial"
)

var defaultCtx = context.Background()

func handleClient(client *tutorial.CalculatorClient) (err error) {
client.Ping(defaultCtx)
fmt.Println("ping()")

sum, _ := client.Add(defaultCtx, 1, 1)
fmt.Print("1+1=", sum, "\n")

work := tutorial.NewWork()
work.Op = tutorial.Operation_DIVIDE
work.Num1 = 1
work.Num2 = 0
quotient, err := client.Calculate(defaultCtx, 1, work)
if err != nil {
switch v := err.(type) {
case *tutorial.InvalidOperation:
fmt.Println("Invalid operation:", v)
default:
fmt.Println("Error during operation:", err)
}
} else {
fmt.Println("Whoa we can divide by 0 with new value:", quotient)
}

work.Op = tutorial.Operation_SUBTRACT
work.Num1 = 15
work.Num2 = 10
diff, err := client.Calculate(defaultCtx, 1, work)
if err != nil {
switch v := err.(type) {
case *tutorial.InvalidOperation:
fmt.Println("Invalid operation:", v)
default:
fmt.Println("Error during operation:", err)
}
return err
} else {
fmt.Print("15-10=", diff, "\n")
}

log, err := client.GetStruct(defaultCtx, 1)
if err != nil {
fmt.Println("Unable to get struct:", err)
return err
} else {
fmt.Println("Check log:", log.Value)
}
return err
}

func runClient(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool, cfg *thrift.TConfiguration) error {
var transport thrift.TTransport
if secure {
transport = thrift.NewTSSLSocketConf(addr, cfg)
} else {
transport = thrift.NewTSocketConf(addr, cfg)
}
transport, err := transportFactory.GetTransport(transport)
if err != nil {
return err
}
defer transport.Close()
if err := transport.Open(); err != nil {
return err
}
iprot := protocolFactory.GetProtocol(transport)
oprot := protocolFactory.GetProtocol(transport)
return handleClient(tutorial.NewCalculatorClient(thrift.NewTStandardClient(iprot, oprot)))
}

Server(服务器)

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
import (
"crypto/tls"
"fmt"

"github.com/apache/thrift/lib/go/thrift"
"github.com/apache/thrift/tutorial/go/gen-go/tutorial"
)

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()
This snippet was generated by Apache Thrift's source tree docs: tutorial/go/src/server.go

Server Handler
import (
"context"
"fmt"
"strconv"

"github.com/apache/thrift/tutorial/go/gen-go/shared"
"github.com/apache/thrift/tutorial/go/gen-go/tutorial"
)

type CalculatorHandler struct {
log map[int]*shared.SharedStruct
}

func NewCalculatorHandler() *CalculatorHandler {
return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)}
}

func (p *CalculatorHandler) Ping(ctx context.Context) (err error) {
fmt.Print("ping()\n")
return nil
}

func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err error) {
fmt.Print("add(", num1, ",", num2, ")\n")
return num1 + num2, nil
}

func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) {
fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n")
switch w.Op {
case tutorial.Operation_ADD:
val = w.Num1 + w.Num2
case tutorial.Operation_SUBTRACT:
val = w.Num1 - w.Num2
case tutorial.Operation_MULTIPLY:
val = w.Num1 * w.Num2
case tutorial.Operation_DIVIDE:
if w.Num2 == 0 {
ouch := tutorial.NewInvalidOperation()
ouch.WhatOp = int32(w.Op)
ouch.Why = "Cannot divide by 0"
err = ouch
return
}
val = w.Num1 / w.Num2
default:
ouch := tutorial.NewInvalidOperation()
ouch.WhatOp = int32(w.Op)
ouch.Why = "Unknown operation"
err = ouch
return
}
entry := shared.NewSharedStruct()
entry.Key = logid
entry.Value = strconv.Itoa(int(val))
k := int(logid)
/*
oldvalue, exists := p.log[k]
if exists {
fmt.Print("Replacing ", oldvalue, " with ", entry, " for key ", k, "\n")
} else {
fmt.Print("Adding ", entry, " for key ", k, "\n")
}
*/
p.log[k] = entry
return val, err
}

func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) {
fmt.Print("getStruct(", key, ")\n")
v := p.log[int(key)]
return v, nil
}

func (p *CalculatorHandler) Zip(ctx context.Context) (err error) {
fmt.Print("zip()\n")
return nil
}