C + + Thrift Detailed tutorials and protobuf contrast __c++

Source: Internet
Author: User
Tags serialization

Recently, thrift and PROTOBUF were used for communication transmission. Before have written about protobuf a blog, specific please click: http://blog.csdn.net/zsk4232000/article/details/50300201, now summed up the compilation of thrift, And make some comparisons with Protobuf. No in-depth research, only describe my use of thrift processes and methods.

Thrift itself encapsulates some of the communications library, supporting the full client/server RPC framework, so the use of thrift to write network communication will be very convenient, but also support the const, TypeDef, etc., so more popular with Thrift Network communication protocol to write.
1.. thrift file Format
Company.thrift Code:

Namespace CPP com.company.project
enum HOBBY
{
    RUNNING = 0,
    badmintion = 1,
    pingpong = 3,
}
struct
person {
    1:required string name;
    2:required i32 age  ;
    3:required string Home;
    4:optional HOBBY HOBBY = HOBBY. RUNNING;
}

Enum FIELD
{
    IT = 0,
    mechine = 1, security
    = 2,
}
struct company
{
    1:required List<person> staff;
    2:required field field;
    3:required i32 Staff_num;
    4:optional i32 rank =  1;
}

Service Tcompanyservice
{person
    getstaffinfo (1:i32 index)
    void Printallstaffname (1:list<person > Staffs)
}

Note: The format of the command space:

Namespace CPP com.company.project     //a
namespace Java com.company.project     //b

A: The command space for the C + + language format translates into namespace com {namespace company{namespace project {
B: For the command space in the Java language format, the conversion to package Com.example.project can not be nested, that is, the structure or the enumeration body cannot be written in other structures, as follows:

struct person
{
    1:required string name;
    2:required i32 age  ;
    3:required string Home;

    Enum HOBBY
    {
        RUNNING = 0,
        badmintion = 1,
        pingpong = 3,
    }

    4:optional HOBBY = HOBBY. RUNNING;
}
Three types of containers are available:
   list< T1: An ordered list of elements of a series of T1 types that can be repeated
   set< T1: An unordered table consisting of elements of a series of T1 types, element unique
   Map < T1, T2 >:key/ Value pair (the type of key is T1 and key is unique, value type is t2)
You can omit modifiers required and optional, but it's best to write, if it's optional, it's best to have a default value. If you want to refer to a type in another thrift file, include (not #include), such as include "Tweet.thrift" and Protobuf differences:
Thrift does not support unsigned integer, PROTOBUF support, Thrift support container, PROTOBUF is not supported, can only be expressed in repeated; Thrift Support Const, TYPEDEF,PROTOBUF not supported; Thrift supports the declaration of the Service interface and can be inherited, protobuf not supported; Writing format is not the same:
      Thrift
      1:required string name;
      2:optional HOBBY HOBBY = HOBBY. RUNNING;

      Protobuf
      Required String name = 1;
      Optional HOBBY HOBBY = 2[default = RUNNING];

2. Thrift compilation

Thrift--gen CPP Company.thrift    //Result code is stored in the Gen-cpp directory thrift--gen
java company.thrift   // The resulting code is stored in the Gen-java directory

In C + +, 7 files are generated:

Company_constants.h  company_constants.cpp: Storing constants
company_types.h      company_types.cpp     : Storing defined Types
TCompanyService.h    TCompanyService.cpp   : Declaration and definition of Client service interface
TCompanyService_server.skeleton.cpp        : Service-side interface implementation, the specific need to modify and add, Only one template is given.

What we need to focus on is:

TCompanyService.h    TCompanyService.cpp    TCompanyService_server.skeleton.cpp

The first two are for the client, the latter for the server, and the name can be modified, it is just a template.

3. Serialization/deserialization

Transport class: Responsible for data transmission
Available options are: Tfiletransport: file (log) transport class, which allows the client to pass files to the server, allowing the server to write the received data to a file. Thttptransport: The use of HTTP transport protocol for data transmission tsocket: The use of TCP socket for data transmission tzlibtransport: Compression after the data transmission, or will receive data decompression

The following classes are mainly decorated with the above categories (using decorative mode) to improve transmission efficiency. Tbufferedtransport: Buffer for the operation of a transport object, that is, to read data from the buffer to transmit it, or to write the data directly into the buffer Tframedtransport: Similar to the Tbufferedtransport, will also buffer the relevant data, while it supports fixed-length data sending and receiving. Tmemorybuffer: Reading and writing data from a buffer protocol class: Responsible for data encoding
Available options are:
Tbinaryprotocol: Binary code
Tjsonprotocol:json Code
Tcompactprotocol: Dense binary coding
TDEBUGPROTOCOL: Organizing data server classes in a user-readable manner
Available options are:
Tsimpleserver: Simple single-threaded server, primarily for testing
Tthreadpoolserver: Multi-threaded servers with standard blocking IO
Tnonblockingserver: Multi-threaded servers using non-blocking IO, tframedtransport must use this type of server

I have not specifically studied, use is the most commonly used.
The following code is one of these:

//serialization template<typename t> void object2string (const T &object, string &buf) {b
    Oost::shared_ptr<tmemorybuffer> Membuffer (New Tmemorybuffer ());
    Boost::shared_ptr<tprotocol> Protocol (new Tbinaryprotocol (Membuffer));
    Object.write (Protocol.get ());
    Buf.clear ();
BUF = Membuffer->getbufferasstring ();  ///deserialization template<typename t> void String2object (const string &buf, T &object) {uint8_t *p = (uint8_t
    *) (Buf.data ());
    uint32_t size = Buf.size ();
    Boost::shared_ptr<tmemorybuffer> Membuffer (New Tmemorybuffer (p,size));
    Boost::shared_ptr<tprotocol> Protocol (new Tbinaryprotocol (Membuffer));
Object.read (Protocol.get ()); }

4. Client-side Authoring
1. You need to include the header file TCompanyService.h, which already contains the header file Company_types.h, so we can use the class defined in. Thrift.
2. In TCompanyService.h and TCompanyService.cpp, a class has been created for us to apply to the client: Tcompanyserviceclient, which implements the interface we declare.
3. Open TCompanyService.cpp, you can see the function body of the interface implementation:

void Tcompanyserviceclient::getstaffinfo (person& _return, const int32_t index)
{
  Send_getstaffinfo ( index);
  Recv_getstaffinfo (_return);
}

void Tcompanyserviceclient::P rintallstaffname (const std::vector<person> & Staffs)
{
  Send_ Printallstaffname (staffs);
  Recv_printallstaffname ();
}

The function body has helped us achieve the sending and receiving, very very convenient.
It should be noted that the return value of the interface we are declaring in. Thrift is returned here as a parameter.

Client code:

#include "gen-cpp/tcompanyservice.h" #include <boost/make_shared.hpp> #include <thrift/transport/ tbuffertransports.h> #include <thrift/transport/TSocket.h> #include <thrift/protocol/tbinaryprotocol.h
> Using namespace std;
using namespace boost;   Using namespace Com::company::p roject;
Corresponds to the namespace Com.company.project using namespace in. Thrift:: Apache::thrift;
Using namespace:: Apache::thrift::p rotocol;

Using namespace:: Apache::thrift::transport;
    void Csocketclient::start () {//Conducting network traffic initialization auto Mysock = boost::make_shared<tsocket> ("10.17.128.19", 7200);
    Boost::shared_ptr<ttransport> Mytransport (New Tbufferedtransport (Mysock));
    Boost::shared_ptr<tprotocol> Myprotoc (New Tbinaryprotocol (Mytransport));   Tcompanyserviceclient client (MYPROTOC);

    Create a client instance Mytransport->open ();
        while (true) {char *p = (char*) malloc (100); if (!cin.getline (p,100)) {cout<< ' please enter some worDs! "
            <<endl;
        Continue

        person person; The service side needs to return the employee who is numbered 2 in all employees; Note: person is here for return information, no need to assign a client.

        Getstaffinfo (person,2);

    cout<<person.name<<endl;
} mytransport->close (); }

5. Server-side writing
In fact, the compiler has generated a server-side overall network communication framework, that is, file Tcompanyservice_ Server.skeleton.cpp, we can copy it to the server project and change it to the name you want. Because this file already implements the main function, you need to delete the original main function.
TCompanyService_server.skeleton.cpp Code:

Class Tcompanyservicehandler:virtual public Tcompanyserviceif {Public:tcompanyservicehandler () {//Your Initia Lization goes here} void Getstaffinfo (person& _return, Const int32_t index) {//Your-Implementation goes he
  Re printf ("getstaffinfo\n"); } void Printallstaffname (const std::vector<person> & staffs) {//Your implementation goes here print
  F ("printallstaffname\n");

}
};
  int main (int argc, char **argv) {int port = 7200;
  Shared_ptr<tcompanyservicehandler> Handler (new Tcompanyservicehandler ());
  Shared_ptr<tprocessor> Processor (new Tcompanyserviceprocessor (handler));
  Shared_ptr<tservertransport> Servertransport (New Tserversocket (port));
  Shared_ptr<ttransportfactory> transportfactory (New Tbufferedtransportfactory ());

  Shared_ptr<tprotocolfactory> protocolfactory (New Tbinaryprotocolfactory ());
  Tsimpleserver Server (processor, Servertransport, Transportfactory, protocolfactory); Server.Serve ();
return 0; }

All we need to do is implement the server-side interface Getstaffinfo () and Printallstaffname (), and of course the implementation given by the main () function is just one of them, and we can modify it as needed, For example, switch simple single-threaded server tsimpleserver to a multithreaded server tthreadpoolserver with standard blocking IO. Here we assume that a company type instance mycompany is known, and there are 1000 employees staff, then we can implement the interface

void Getstaffinfo (person& _return, Const int32_t index) {
    if (Index > 1000)
    {
        cout<< "can not Find the Staff <<endl;
        return;
    }
    _return = mycompany.staff.at (index);
}

The main () function blocks on Server.serve () for receiving and sending. For example, we call on the client Interface for Getstaffinfo (), the server () function received after the decision is which interface in the Send, know is the interface Getstaffinfo (), the call on the server Interface Implementation Getstaffinfo () for data processing, And then send the results. All of this has been done for us, we do not have to worry about the process of communication, just a good write service-side data processing.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.