5

I am developing a tiny server loop for a bigger software but it doesn't work as I want it to do.

When the user types in ".quit" I want the software to stop this threaded server loop:

try {

while (true) {
      acceptor.accept(socket);
      const size_t buffersize = 1024;
      char data[buffersize+1] = {0};
      data[socket.read_some(boost::asio::buffer(data,buffersize))] = '\0'; // Write data & place terminator
      boost::thread asyncWriting(boost::bind( &myClass::writeToFile, this ));
      socket.close();
}

} catch(const boost::system::system_error& e) {
    cout << "Boost System Error: " << e.what() << endl;
}

I start the thread the following way:

serverThread = boost::shared_ptr<boost::thread>( new boost::thread(boost::bind( &myClass::startServer, this )) );

But I have problems stopping the "server". No matter if I interrupt the thread, close the socket and/or the acceptor or just break the program Boost throws the error:

 Bad file descriptor

It doesn't occurs every time but often and I want to fix that issue and not just ignore it.

Can you help me how to shut this down clean?

Paul
  • 1,295
  • 2
  • 11
  • 26
  • it would be helpful if you could attach a debugger and tell us where the exception is thrown. There are multiple asio methods that can throw a `boost::system::system_error` with an error code of `boost::system::errc::bad_file_descriptor`. – Sam Miller Jan 16 '11 at 01:44

1 Answers1

2

Typically servers are written using asynchronous methods

  • async_accept
  • async_read
  • async_write

in which case the suggested technique to shutdown all pending asynchronous operations is to stop the io_service's event processing loop. Note that you should pay special attention to the ~io_service documentation

The destruction sequence described above permits programs to simplify their resource management by using shared_ptr<>. Where an object's lifetime is tied to the lifetime of a connection (or some other sequence of asynchronous operations), a shared_ptr to the object would be bound into the handlers for all asynchronous operations associated with it.

It's not obvious to me based on the limited code that you've posted where your problem is, I'd suggest posting more code or running what you have under valgrind as it will most likely expose some problems.

I answered a similar question a few days ago that you might find useful

Community
  • 1
  • 1
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • Hi Sam, thanks for your answer! I also found the question in my Google search today but wasn't really sure whether I should use this method. But I'll take a look, make it asynchronous and write my experiences here. – Paul Jan 16 '11 at 11:46
  • Worked perfectly. It was essential to know that you can bind the acceptor and end it safely with the help of io_service.stop(); – Paul Jan 16 '11 at 15:16
  • Hi Sam, I checked out valgrind after I switched to asynchronous acceptor actions and used this example (http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp) as a pattern. It turned out that I have some leaks because I alloc sessions (new session(io_service);) and never release them because they are lost in async threads and/or their pointers are missing. That's why my process is growing and growing. How do I fix that? – Paul Jan 16 '11 at 17:24
  • @Paul probably best to ask a new question and post your new code in there. Tag it with `boost-asio` and `valgrind`. – Sam Miller Jan 16 '11 at 17:38