Apache Thrift is a remote procedure call mechanism for heterogeneous environments. A platform independent interface description language is used to describe the remotely accessible interfaces. The runtime environment supports multiple encodings over multiple transports.
namespace cpp org.example namespace java org.example enum AnEnum { ONE = 1, TWO = 2, THREE = 3 } struct SomeMessage { 1: bool aBooleanField, 2: i8 aByteField, 3: i16 aShortIntField, 4: i32 aNormalIntField, 5: i64 aLongIntField, 10: double aDoubleField, 20: string aStringField, 22: binary aBinaryField, // Fields can have default values. 100: AnEnum anEnumFieldWithDefault = AnEnum.THREE, // Fields can be optional. 200: optional i16 anOptionalIntField } // Exceptions are structures too. exception SomeException { 1: list<string> aStringList, 2: set<i8> aByteSet, 3: map<i16, string> aMap } service AnInterface { void ping (), bool aMethod (1: i16 argShort, 2: i64 argLong), oneway void aOnewayMethod (1: SomeMessage message) } service AnotherInterface extends AnInterface { void yetAnotherMethod (1: SomeMessage message) throws (1: SomeException ex) }
Namespaces per language
A spectrum of basic types
Containers for other types
Fields can be optional
Explicit field and argument identifiers for versioning
Methods can be oneway
Methods can throw exceptions
Method Implementation.
class ExampleHandler : virtual public ExampleIf { void printString (const std::string &text) override { // Method implementation goes here ... } ... }
Server Initialization.
// Handler is the user defined implementation. std::shared_ptr<ExampleHandler> handler (new ExampleHandler ()); // Processor is responsible for decoding function arguments and invoking the handler. std::shared_ptr<ExampleProcessor> processor (new ExampleProcessor (handler)); // Transport provides reading and writing of byte buffers. std::shared_ptr<TServerTransport> transport (new TServerSocket (SERVER_PORT)); // Buffered transport is a wrapper for another transport object. std::shared_ptr<TTransportFactory> transport_factory (new TBufferedTransportFactory ()); // Protocol provides reading and writing of individual types on top of transport. std::shared_ptr<TProtocolFactory> protocol_factory (new TBinaryProtocolFactory ()); // New connections use their own transport and protocol instances hence the factories. std::shared_ptr<TServer> server (new TSimpleServer (processor, transport, transport_factory, protocol_factory)); server->serve ();
Public read
and write
methods on generated transport types
Multiple transports available
Plain socket
Socket with SSL
Socket with HTTP
Socket with WebSocket
Wrapper for zlib compression
File and pipe
Memory buffer
Multiple protocols available
JSON
Simple binary encoding
Compact binary encoding
Wrapper for serving multiple services
Multiple servers available
Single main thread
Thread per connection
Thread pool with fixed size
Thread pool with fixed size and dedicated dispatcher
The file and memory buffer transports can be used for simple serialization without performing remote calls.
The simple binary encoding protocol stores primitive types in fixed length format with configurable byte ordering. Structure fields are stored with type and identifier also in fixed length format. Containers are similarly straightforward. See https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md for details on the simple binary encoding protocol.
The compact binary encoding protocol stores primitive integer types in variable length format. Structure fields store identifiers as deltas where possible and use variable length format where not. Containers store type and size together for small enough sizes and use variable length format otherwise. See https://github.com/apache/thrift/blob/master/doc/specs/thrift-compact-protocol.md for details on the compact binary encoding protocol.
This note looks at the example from https://github.com/d-iii-s/teaching-middleware/tree/master/src/thrift-basic-server in more detail, the code snippets were generated with Thrift 0.14. On the server side, the ExampleHandler
class inherits from ExampleIf
, a generated abstract class with the printString
method that reflects the interface definition:
class ExampleIf { public: virtual ~ExampleIf () {} virtual void printString (const std::string& text) = 0; };
The ExampleIf
class is what the generated ExampleProcessor
class calls to deliver method invocations:
void ExampleProcessor::process_printString (int32_t seqid, TProtocol* iprot, TProtocol* oprot, void* callContext) { ... Example_printString_args args; args.read (iprot); iprot->readMessageEnd (); uint32_t bytes = iprot->getTransport ()->readEnd (); ... Example_printString_result result; try { iface_->printString (args.text); } catch (const std::exception& e) { ... TApplicationException x (e.what ()); oprot->writeMessageBegin ("printString", T_EXCEPTION, seqid); x.write (oprot); oprot->writeMessageEnd (); oprot->getTransport ()->writeEnd (); oprot->getTransport ()->flush (); return; } ... oprot->writeMessageBegin ("printString", T_REPLY, seqid); result.write (oprot); oprot->writeMessageEnd (); bytes = oprot->getTransport ()->writeEnd (); oprot->getTransport ()->flush (); ... } uint32_t Example_printString_args::read (TProtocol* iprot) { ... xfer += iprot->readStructBegin(fname); bool isset_text = false; while (true) { xfer += iprot->readFieldBegin (fname, ftype, fid); if (ftype == T_STOP) { break; } switch (fid) { case 1: if (ftype == T_STRING) { xfer += iprot->readString (this->text); isset_text = true; } else { xfer += iprot->skip (ftype); } break; default: xfer += iprot->skip(ftype); break; } xfer += iprot->readFieldEnd (); } xfer += iprot->readStructEnd (); if (!isset_text) throw TProtocolException (INVALID_DATA); return xfer; }
Client Initialization.
// Transport provides reading and writing of byte buffers. std::shared_ptr<TTransport> socket (new TSocket (SERVER_ADDR, SERVER_PORT)); // Buffered transport is a wrapper for another transport object. std::shared_ptr<TTransport> transport (new TBufferedTransport (socket)); // Protocol provides reading and writing of individual types on top of transport. std::shared_ptr<TProtocol> protocol (new TBinaryProtocol (transport));
Method Call.
std::shared_ptr<ExampleClient> client (new ExampleClient (protocol)); client->printString ("Hello from Thrift in C++ !");
This note looks at the example from https://github.com/d-iii-s/teaching-middleware/tree/master/src/thrift-basic-server in more detail, the code snippets were generated with Thrift 0.14. On the client side, the ExampleClient
class is a generated stub class with the printString
method responsible for the remote method invocation:
class ExampleClient : virtual public ExampleIf { public: void printString (const std::string& text); void send_printString (const std::string& text); void recv_printString (); ... }; void ExampleClient::send_printString (const std::string& text) { int32_t cseqid = 0; oprot_->writeMessageBegin ("printString", T_CALL, cseqid); Example_printString_pargs args; args.text = &text; args.write (oprot_); oprot_->writeMessageEnd (); oprot_->getTransport ()->writeEnd (); oprot_->getTransport ()->flush (); } void ExampleClient::recv_printString () { ... iprot_->readMessageBegin (fname, mtype, rseqid); if (mtype == T_EXCEPTION) { TApplicationException x; x.read (iprot_); iprot_->readMessageEnd (); iprot_->getTransport ()->readEnd (); throw x; } if (mtype != T_REPLY) { iprot_->skip (T_STRUCT); iprot_->readMessageEnd (); iprot_->getTransport ()->readEnd (); } if (fname.compare ("printString") != 0) { iprot_->skip (T_STRUCT); iprot_->readMessageEnd (); iprot_->getTransport ()->readEnd (); } Example_printString_presult result; result.read (iprot_); iprot_->readMessageEnd (); iprot_->getTransport ()->readEnd (); return; } int32_t Example_printString_args::write (TProtocol* oprot) const { ... xfer += oprot->writeStructBegin ("Example_printString_args"); xfer += oprot->writeFieldBegin ("text", T_STRING, 1); xfer += oprot->writeString (this->text); xfer += oprot->writeFieldEnd (); xfer += oprot->writeFieldStop (); xfer += oprot->writeStructEnd (); return xfer; }
The Apache Thrift Project Home Page. https://thrift.apache.org