Search code examples
c++apacherpcthrift-protocol

Implementing a Server/Client with HTTP protocol with Apache Thrift


I'm new to apache thrift. I wanted to use it to help me implement a server that accepts input from a client, parse it and based on that direct it to the proper function which in turn would return a response for that specific request.

For example:

  1. Client sends: /get_list/1 (This should return values within list#1 from server)
  2. Server parses input to the following: get_list && 1
  3. Server maps this to a get_list_req which is a struct that has only one parameter: i32_t id (which in this case would be 1)
  4. Server sends this to the getListReq function which should return get_list_resp struct which has 1 parameter: list list_content.

Now I have defined the structs necessary in the mylist.thrift:

struct TGetListRequest {
    1: i32_t id,
}
struct TGetListResponse {
    1: string response_code, //FAIL or SUCCESS
    2: list<string> nodes, 
}

service TmyListService {

    TGetListResponse getListReq( 1:TGetListRequest arg ),
}

Now this generates the necessary files:

TmyListService_server.skeleton.cpp 
TmyListService.cpp
TmyListService.h
mylistconstants.cpp
mylistconstants.h
mylisttypes.cpp
mylisttypes.h

First file's content is copied to TmyListService_server.cpp where the class is implemented with its method: getListReq as follows:

class TGetListRequestHandler: public TGetListRequestIf {
public:
    TGetListResponse getListReq(TGetListRequest arg){
        ...
    }
};

I have it provided in it the following code to start server in main() function:

int main(int argc, char **argv)  {
  int port = 9090;
  shared_ptr<TmyListServiceHandler> handler(new TmyListServiceHandler());
  shared_ptr<TProcessor> processor(new TmyListServiceProcessor(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;
}

Now comes the tricky part for me:

  1. Where do I implement the parsing of the input coming from a client to the server? I was told that it is simple implementation using thrift without the need to write your our parser or use a parser generator? I cannot seem to figure this one out? Where am I telling my server what to do with input i.e. which Req function to direct it to?

  2. In terms of implementing the client, I have the following:

    int main(int argc, char **argv) {
     boost::shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
     boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
     boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    
     TmyListServiceClient client(protocol);
     TGetListRequest arg;
     arg.id = 1;
     TGetListResponse argz;
     transport->open();
     client.send_getListReq( arg );
     printf("DONE SEDNING");
     client.recv_getListReq( argz );
     transport->close();
    
    return 0;
    }
    

This basically does nothing aside from opening the client connection. It doesn't accept any input at all. I'm sure this is also related to the implementation of the processing logic within the server first, but what should I be doing here to have a client ready to be tested against the server?


Solution

  • You're almost done!

    On your server you show this code:

    shared_ptr<TProcessor> processor(new TmyListServiceProcessor(handler));

    Where's the handler?! This is the class that implements your service.

    Something like:

    class TmyListServiceHandler: public TmyListServiceIf { public: virtual TGetListResponse getListReq(TGetListRequest arg) override { } };

    The base for your service (TmyListServiceIf) is generated in: TmyListService.h

    >

    Looking at the edits you made to the question I think you still have a handler issue. The Handler class is declared: TGetListRequestHandler in the new code you added.

    Yet you are constructing TmyListServiceHandler in the main function of the server. I have seen this happen when people change things in the IDL and regenerate code without deleting the old output. You end up with two different definitions of things. You need to be using TmyListServiceHandler everywhere.

    Per your IDL TGetListRequest is a struct and should not have a handler.