Introduction

The Apache Thrift is a software framework used to facilitate binary communication. Based on RPC (remote procedure call) it was developed by Facebook and provides the complete stack for creation clients/server solutions. Cross-language is one of the most useful feature of Thrift by providing a lot of supported programming languages (C#,C++, Java, Php, Node.js, Cocoa, …). The common struct and service should be written in .thrift files using the interface definition language of the framework.

Here we want to create a simple client/server solution first in C++ then between C++ and C#.

 

I. Downloads

Example: Visual Studio Solution Sources
Download

Example: Visual Studio Solution Sources + Executables
Download

Thrift compiler (used to generate class files from a *.thrift definition file):
http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.2/thrift-0.9.2.exe

Thrift sources (Extract thrift-0.9.2.tar.gz)
http://wwwftp.ciril.fr/pub/apache/thrift/0.9.2/thrift-0.9.2.tar.gz

Boost
http://cznic.dl.sourceforge.net/project/boost/boost-binaries/1.57.0/boost_1_57_0-msvc-12.0-64.exe

OpenSSL (compiled libraries for Visual Studio)
http://www.npcglib.org/~stathis/blog/precompiled-openssl/

LibEvent
http://softlayer-ams.dl.sourceforge.net/project/levent/libevent/libevent-2.0/libevent-2.0.22-stable.tar.gz

 

II. Setup prerequisites

Boost installation

boost

OpenSSL

You can download OpenSSL sources then compile it or download directly the compiled library on the following url: http://www.npcglib.org/~stathis/blog/precompiled-openssl/

Select the version which targeted the MSVC 2013 compiler.

openssl

Extract “openssl-1.0.1l-vs2013.7z” into “C:\libraries\openssl-1.0.1l-vs2013”

LibEvent

Download LibEvent sources at the following url: http://softlayer-ams.dl.sourceforge.net/project/levent/libevent/libevent-2.0/libevent-2.0.22-stable.tar.gz

Extract “libevent-2.0.22-stable.tar.gz” into ”C:\libraries\libevent-2.0.22-stable”

Compile the library:

Open a visual command prompt “C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\VS2013 x64 Cross Tools Command Prompt”

Then navigate to the sources folder:

>cd C:\libraries\libevent-2.0.22-stable

Compile using the nmake file:

> nmake -f Makefile.nmake

nmake

“C:\libraries\libevent-2.0.22-stable” contains 3 static libraries:

  • libevent.lib
  • libevent_extras.lib
  • libevent_core.lib

III. Compile thrift sources in Cpp

Now, all prerequisites libraries are stored in the “C:\libraries” folder.

Download thrift sources (thrift-0.9.2.tar.gz) on http://wwwftp.ciril.fr/pub/apache/thrift/0.9.2/thrift-0.9.2.tar.gz then extract into (C:\libraries \thrift-0.9.2)

lib folder

 

 

Open the solution located at “C:\libraries \thrift-0.9.2\lib\cpp\thrift.sln”

I’m currently using the Visual Studio 2015 CTP6, therefore I get the following error when compiling the 2 projects (libthrift, libthriftnb).

vs2015_error

For both of them, go to project properties then change the option “General > Platform Toolset” from “Visual Studio 2015 (v140)” to “Visual Studio 2013 (v120)”

fix_vs2015

 

Compile again, we get new errors (Cannot open include file: ‘boost/static_assert.hpp’, …)

thrift_compilation

We have to resolve all dependencies (Boost, OpenSSL, LibEvent)

Compile libthrift

Define “Additional include directories”

Open the project property pages:

libthrift_additional_include

Then set “C/C++ > General > Additional Include Directories” set the following values:

  • C:\libraries\libevent-2.0.22-stable\include
  • C:\libraries\openssl-1.0.1l-vs2013\include
  • C:\libraries\boost_1_57_0
  • C:\libraries\boost_1_57_0\boost

additional_include_window

 

Define “Additional library directories”

Open the project property pages:

library directories

Then set “Librarian > General > Additional Library Directories” set the following values:

  • C:\libraries\openssl-1.0.1l-vs2013\lib64
  • C:\libraries\boost_1_57_0\lib64-msvc-12.0
  • C:\libraries\libevent-2.0.22-stable

library directories_window

 

Rebuild the solution check that libthrift compile well.

Compile libthriftnb

Define “Additional include directories”

Open the project property pages then set “C/C++ > General > Additional Include Directories” set the following values:

  • C:\libraries\libevent-2.0.22-stable\include
  • C:\libraries\libevent-2.0.22-stable\WIN32-Code
  • C:\libraries\libevent-2.0.22-stable
  • C:\libraries\boost_1_57_0

Define “Additional library directories”

Open the project property pages then set “Librarian > General > Additional Library Directories” set the following values:

  • C:\libraries\libevent-2.0.22-stable
  • C:\libraries\boost_1_57_0\lib64-msvc-12.0

Rebuild the solution check that libthriftnb compile well.

 

IV. Generation of the “POCService”

Define our service definition

First of all we have to write a .thrift file that contains objects and service definitions.

Read the following document for detailed explanations http://thrift.apache.org/docs/idl

In our example we want to create a simple service to add and get objects named “ObjectPosition”. The following file contains our struct definition and the POCService methods.

pocservice.thrift:

/**
* Define our sample service
*
*/
struct ObjectPosition {
  1: double X = 0,
  2: double Y = 0,
  3: string Identifier,
}
 
service POCService {
  void ping(),
  void AddObjectPosition(1:ObjectPosition position),
  list<ObjectPosition> GetAllObjectPositions()
}

 

Generate C++ and C# classes

Open a command prompt then change directory to the same folder as pocservice.thrift. Execute the following commands to generate C++ and C# classes:

>thrift-0.9.2.exe --gen cpp pocservice.thrift
>thrift-0.9.2.exe --gen csharp pocservice.thrift

generate_thrift

 

Two folders were created: “gen-cpp” and “gen-csharp”.

V. Create our client/server solution

We will create a solution which included 3 projects:

  • ThriftPOC.Server
  • ThriftPOC.Client
  • ThriftPOC.Shared

Server will listen to calls
Client will perform calls
Shared will contains common objects definition between server and client projects.

Shared project

Creation

Create a new “Win32 project”

create_shared_1

Select “Static library” and uncheck “precompiled header” and “Security Development Lifecycle (SDL) checks”.

create_shared_2

Our shared project is created, just add the generated files from the “gen-cpp” folder (except “POCService_server.skeleton.cpp”)


create_shared_3

Configuration

Go to project property pages to set “Platform Toolset” to “Visual Studio 2013 (v120)”

shared_config_1

The generated classes reference boost and the thrift framework. We have to define these prerequisites in project option.

Define “Additional include directories”

Open the project property pages then set “C/C++ > General > Additional Include Directories” set the following values:

  • C:\libraries\boost_1_57_0
  • C:\libraries\thrift-0.9.2\lib\cpp\src

shared_config_2

Define “Additional library directories”

Open the project property pages then set “Librarian > General > Additional Library Directories” set the following values:

  • C:\libraries\boost_1_57_0\lib64-msvc-12.0
  • C:\libraries\thrift-0.9.2\lib\cpp\Debug

shared_config_3

 

 

C++ Server project

Creation

Now we will create the server project. Select Win32 project.

create_server_1

Select a “Console application” then check “Empty project” (we will used the generated service skeleton generated by thrift). Uncheck “Security Development Lifecycle (SDL) checks”.

create_server_3

Configuration

1. The project is created, we need to add a reference to the shared project:

server_config1

2. Platform Toolset

In project property pages select Platform Toolset to “Visual Studio 2013 (v120)”.

3. Additional Include Directories

C/C++ > Additional Include Directories set the values:

  • C:\libraries\boost_1_57_0
  • C:\libraries\thrift-0.9.2\lib\cpp\src\thrift\windows
  • C:\libraries\thrift-0.9.2\lib\cpp\src

server_config24. Additional Library Directories

Linker > General > Additional Library Directories:

  • C:\libraries\boost_1_57_0\lib64-msvc-12.0
  • C:\libraries\thrift-0.9.2\lib\cpp\Debug

server_config35. Additional Dependencies

 

Linker > Input > Additional Dependencies:

  • libboost_thread-vc120-mt-gd-1_57.lib
  • libboost_chrono-vc120-mt-gd-1_57.lib
  • libthrift.lib
    server_config4

 

Code

Thrift generated for us a server skeleton named “POCService_server.skeleton.cpp”. It contains a fake implementation of our service methods.

First of all, copy the file “POCService_server.skeleton.cpp” to the project. We need to make some changes.

Includes

We need to change

#include "POCService.h"

to

#include "../POCService.Shared/pocservice_types.h"
#include "../POCService.Shared/POCService.h"

To display some information on the console we add the iostream library:

#include <iostream>
...
using namespace std;

Override POCServiceHandler implementation

We override the generated class to implement the service definition:

class POCServiceHandler : virtual public POCServiceIf {
public:
	POCServiceHandler() {
	}
 
	void ping() {
		printf("ping\n");
	}
 
	void AddObjectPosition(const ObjectPosition& position) {
		dataInMemory.push_back(position);
		printf("AddObjectPosition\n");
	}
 
	void GetAllObjectPositions(std::vector & _return) {
		printf("GetAllObjectPositions\n");
		_return = dataInMemory;
	}
 
private:
	vector dataInMemory;
};

Update the main function

With the addition of std library, we have to specify the namespace of shared_ptr. Moreover we display a message that indicates server starting and ending.

int main(int argc, char **argv) {
	int port = 9090;
	boost::shared_ptr handler(new POCServiceHandler());
	boost::shared_ptr processor(new POCServiceProcessor(handler));
	boost::shared_ptr serverTransport(new TServerSocket(port));
	boost::shared_ptr transportFactory(new TBufferedTransportFactory());
	boost::shared_ptr protocolFactory(new TBinaryProtocolFactory());
 
	TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
	cout << "Starting the server..." << endl;
	server.serve();
	cout << "Done." << endl;
	return 0;
}

Let’s compile and launch the server project.

server_launch

Everythings looks good, our server project is ready.

C++ Client project

Creation

Now we will create the client project. Select Win32 project.

create_client_1

 

Select a “Console application” then check “Empty project” (we will used the generated service skeleton generated by thrift). Uncheck “Security Development Lifecycle (SDL) checks”.

Configuration

1. The project is created, we need to add a reference to the shared project:

client_config_12. Platform Toolset

In project property pages select Platform Toolset to “Visual Studio 2013 (v120)”.

3. Additional Include Directories

C/C++ > Additional Include Directories set the values:

  • C:\libraries\boost_1_57_0
  • C:\libraries\thrift-0.9.2\lib\cpp\src\thrift\windows
  • C:\libraries\thrift-0.9.2\lib\cpp\src

client_config_2

4. Additional Library Directories

Linker > General > Additional Library Directories:

  • C:\libraries\boost_1_57_0\lib64-msvc-12.0
  • C:\libraries\thrift-0.9.2\lib\cpp\Debug

client_config_3

5. Additional Dependencies

Linker > Input > Additional Dependencies:

  • libboost_thread-vc120-mt-gd-1_57.lib
  • libboost_chrono-vc120-mt-gd-1_57.lib
  • libthrift.lib

Code

Add a new file to the project named “POCClient.cpp”

client_code

We write a small client that will process calls to the server:

 

#include <iostream>
 
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include "..\POCService.Shared\pocservice_types.h"
#include "..\POCService.Shared\POCService.h"
 
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
 
int main()
{
	boost::shared_ptr socket(new TSocket("localhost", 9090));
	boost::shared_ptr transport(new TBufferedTransport(socket));
	boost::shared_ptr protocol(new TBinaryProtocol(transport));
 
	POCServiceClient client(protocol);
 
	try {
		transport->open();
		ObjectPosition obj;
		obj.X = 10;
		obj.Y = 20;
		obj.Identifier = "Olivier";
 
		client.AddObjectPosition(obj);
		cout << "AddObjectPosition()" << endl;
 
		vector objects;
		client.GetAllObjectPositions(objects);
 
		cout << "Size of vector: " << objects.size() << endl;
	}
	catch (TException& tx) {
		cout << "ERROR: " << tx.what() << endl;
	}
	return 0;
}

 

 

Test

Launch the server:

client_test

Then launch our client (set up a breakpoint in the main):

client_test2

 

C# Client project

To validate cross-languages support, we create a C# project.

Creation

csharp_create

 

Configuration

We need to add a reference to the Thrift library framework.

Open the solution located at “C:\libraries\thrift-0.9.2\lib\csharp\src\Thrift.sln” then compile it. “Thrift.dll” appears in the Debug folder:

csharp_config1

 

Go back to the POCService solution then add a reference to the fresh build Thrift.dll

csharp_config2

 

Code

Go to the “gen-csharp” folder then copy “ObjectPosition.cs” and “POCService.cs” to the new project folder.

Let’s build, we get an error “The namespace ‘<global namespace>’ already contains a definition for ‘POCService’”, we just have to rename the POCService to POCServiceC.

Go to Program.cs file then perform calls to the server:

Add the following using:

using Thrift.Transport;
using Thrift.Protocol;

 

Write the main method:

static void Main(string[] args)
{
    //Thrift.Transport.TTransport Transport
    TTransport transport = new TSocket("localhost", 9090);
    transport.Open();
    TProtocol protocol = new TBinaryProtocol(transport);
 
    POCServiceC.Client client = new POCServiceC.Client(protocol);
 
    //call Ping()
    client.ping();
    Console.WriteLine("Ping");
 
    //call AddObjectPosition(obj);
    ObjectPosition obj = new ObjectPosition();
    obj.X = 20;
    obj.Y = 30;
    obj.Identifier = "Olivier";
    client.AddObjectPosition(obj);
    Console.WriteLine("AddObjectPosition");
 
    //call AddObjectPosition(obj);
    List res = client.GetAllObjectPositions();
    Console.WriteLine("Number of positions: " + res.Count);
    Console.ReadLine();
}

 

Test

csharp_test

Last modified: 23 March 2015

Author

Comments

Write a Reply or Comment

Your email address will not be published.