You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@thrift.apache.org by Qianqian JIAO <wi...@staff.easou.com> on 2011/09/20 03:46:12 UTC

[C++] TSimpleServer fails to exit after 'stop()' has been called when the client does not close the connection to the server.

Hello,

 

I found a problem of TSimpleServer: if the client does not close the
connection to the server, after the 'stop()' has been called, the
TSimpleServer still runs. Here is my code, the environment is
thrift-0.7.0@debian 6 x86 32bit.

 

simple.thrift

namespace cpp simple

service simple_service {

                string echo(1:string msg)

}

 

client.cpp

#include <iostream>

#include <sstream>

#include <string>

#include "simple_service.h"

#include <transport/TSocket.h>

#include <transport/TBufferTransports.h>

#include <protocol/TBinaryProtocol.h>

 

 

using namespace std;

using namespace ::apache::thrift;

using namespace ::apache::thrift::protocol;

using namespace ::apache::thrift::transport;

using boost::shared_ptr;

using namespace simple;

 

 

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));

 

  simple_serviceClient client(protocol);

  transport->open();

  for (int i=0; i<10000; i++) {

    stringstream ss;

    ss << i;

    string echo, msg(ss.str());

    client.echo(echo, msg);

    cout << "msg=" << msg << " echo=" << echo << endl;

    sleep(1);

  }

  transport->close();

 

  return 0;

}

 

server.cpp

#include <iostream>

#include "simple_service.h"

#include <protocol/TBinaryProtocol.h>

#include <server/TSimpleServer.h>

#include <transport/TServerSocket.h>

#include <transport/TBufferTransports.h>

#include <concurrency/Thread.h>

#include <concurrency/PosixThreadFactory.h>

 

 

using namespace std;

using namespace ::apache::thrift;

using namespace ::apache::thrift::protocol;

using namespace ::apache::thrift::transport;

using namespace ::apache::thrift::server;

using namespace ::apache::thrift::concurrency;

using boost::shared_ptr;

using namespace simple;

 

class simple_serviceHandler : virtual public simple_serviceIf {

public:

  simple_serviceHandler() {

    // Your initialization goes here

  }

 

  void echo(std::string& _return, const std::string& msg) {

    _return = msg;

  }

 

};

class StopTrigger : public Runnable {

public:

  StopTrigger(TSimpleServer *server) : server_(server) { }

  void run() {

    // sleep a while and start the client during this short time.

    sleep(10);

    cout << "calling TSimpleServer::stop()." << endl;

    server_->stop();

  }

 

private:

  TSimpleServer *server_;

};

int main(int argc, char **argv) {

  int port = 9090;

  shared_ptr<simple_serviceHandler> handler(new simple_serviceHandler());

  shared_ptr<TProcessor> processor(new simple_serviceProcessor(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);

 

  PosixThreadFactory threadFactory = PosixThreadFactory();

  threadFactory.setDetached(false);

  shared_ptr<StopTrigger> stop_trigger(new StopTrigger(&server));

  shared_ptr<Thread> stop_thread = threadFactory.newThread(stop_trigger);

  stop_thread->start();

 

  server.serve();

  cout << "the server is stopped" << endl;

  stop_thread->join();

  return 0;

}

 

Result:

First, I started the server,

>./server

Then I opened another terminal and started the client with 10 seconds

>./client

 

The output of the server is:

calling TSimpleServer::stop().

The output of the client is:

msg=0 echo=0

msg=1 echo=1

msg=2 echo=2

msg=3 echo=3

msg=4 echo=4

msg=5 echo=5

msg=6 echo=6

msg=7 echo=7

..

We can see that the "the server is stopped" never outputs in the server,
which means that the server is not stopped after the 'stop()' has been
called.

But after I sent a "Ctrl+C" to the client to stop it, the "the server is
stopped" printed at last and the server exit. So my conclusion is that: When
the client has not closed the connection, the server cannot stop even if the
'stop()' has been called.

 

I checked the source code of TSimpleServer, found that after it accepts the
client, it simply loops for ever to process the RPC from client unless the
client closes the connection. The 'stop_' variable which is set to 'true' in
'stop()' is ignored in the loop. Here is the code in TSimpleServer.cpp,

99       for (;;) {

100         if (eventHandler_ != NULL) {

101           eventHandler_->processContext(connectionContext, client);

102         }

103         if (!processor_->process(inputProtocol, outputProtocol,
connectionContext) ||

104             // Peek ahead, is the remote side closed?

105             !inputProtocol->getTransport()->peek()) {

106           break;

107         }

108       }

 

I have a idea to solve this problem: adding the 'stop_' as the loop
condition in line:99.

99       for (;stop_;) {

              ...

          }

 

I modified the code myself and have tested it, it works fine. So could
anyone can give me some suggestions about this issue. Thanks!

 

 

2011-09-19

Qianqian JIAO