0

can you help me with little problem?

I have 2 class: Form1 async_srv

When i start application, Form1 create async_srv instance. And listening my socket, all recieved data sending to main class and return answer from her. When get -1, i want destoy acceptor/service/thread and my Application. But this not going. Any suggestions?

My async_srv.h

#include "Form1.h"
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
typedef boost::shared_ptr<boost::asio::ip::tcp::acceptor> acc_ptr;


class async_srv
{
    private:
    boost::thread* srv_thread;
    boost::asio::streambuf response;
    std::stringstream s;
    int stop;
    TForm* ourForm;
    boost::shared_ptr<boost::asio::io_service> m_ioservice;

    protected:
    void start();
    void start_accept(acc_ptr acc,socket_ptr sock);
    void handle_accept(acc_ptr acc, socket_ptr sock);

    public:
    __fastcall async_srv(TForm* Form1);
    void kill(); 

};

My async_srv.cpp

fastcall async_srv::async_srv(TForm* Form1): m_ioservice(boost::make_shared<boost::asio::io_service>())
{
 //create Pointer to main form
ourForm = Form1;
 //create thread to async recieve for realease this class
srv_thread = new boost::thread(boost::bind(&async_srv::start, this));
}

void async_srv::start()
{
 //create acceptor, and socket.
acc_ptr acc(new boost::asio::ip::tcp::acceptor(*m_ioservice, ep));
socket_ptr sock(new boost::asio::ip::tcp::socket(*m_ioservice));

//start_accept
start_accept(acc,sock);
m_ioservice->run();
}

void async_srv::start_accept(acc_ptr acc,socket_ptr sock)
{
  // async accept
  acc->async_accept(*sock, boost::bind(&async_srv::handle_accept, this, acc, sock));
}

void async_srv::handle_accept(acc_ptr acc, socket_ptr sock)
{
    //loop for recieve data
    while (boost::asio::read(*sock, response, boost::asio::transfer_at_least(1), error))
    s << &response;

    if (s.str() != "")
      {
       //recieve answer from main
      stop = ourForm->update(s.str());
         if(stop == -1)
                  {
                               //kill our class and application
                  acc->close();
                  kill();
                  Application->Terminate();
                  return;
                  }
      }

    s.str(std::string());
    response.consume(response.size());
    start_accept(acc,sock);
}

void async_srv::kill()
{
m_ioservice->stop();
srv_thread->~thread();
}
Igor R.
  • 14,716
  • 2
  • 49
  • 83
r1se
  • 67
  • 1
  • 1
  • 6
  • 1
    Manually calling the destructor of `srv_thread` sounds like an outstandingly bad idea. Also, could you post an [SSCCE](http://www.sscce.org/), as it is currently not clear how your `async_src` class is being used. – ComicSansMS Mar 05 '14 at 11:50
  • killing thread not main problem, i can use interupption instead destructor. Main problem, service don't stop accepting aftser stop() – r1se Mar 05 '14 at 11:56
  • async_src used for recieved data from tcp/ip socket. – r1se Mar 05 '14 at 11:58
  • Are you certain `kill()` is being invoked? Just glancing at the code, if `sock` closes without any data or `ourForm->update()` returns any value other than `-1` the first time it is invoked within the chain, then a tight asynchronous chain forms between `start_accept()` and `handle_accept()` due to operations failing because of `sock`'s state. The accept operation will immediately fail because `sock` is open, and the read operation will immediately fail because end of file, leaving the `s.str()` empty and never querying the form again. – Tanner Sansbury Mar 07 '14 at 16:55
  • My mistake was in calling start_accept method on the my handle, just replace "start_accept(acc,sock)" for create new "async->accept", and all work fine. – r1se Mar 13 '14 at 15:14

1 Answers1

1

If you want to stop accepting new connections - make the acceptor a member and close it when needed:

void async_srv::kill()
{
  // avoid closing from another thread
  m_acceptor.get_io_service().post(()[this] { m_acceptor->close(); });
}

If m_ioservice serves the acceptor only, closing it will break async_accept-->handle_accept-->... chain and eventually make m_ioservice::run() exit, as it runs out of work. (Of course, you should not call ~thread.)

Igor R.
  • 14,716
  • 2
  • 49
  • 83
  • i used boost 1.39, my acceptor doesn't have method get_io_service() – r1se Mar 05 '14 at 13:27
  • @user2393500 It was called `io_service()`. – Igor R. Mar 05 '14 at 13:47
  • i know, sorry my mistake. IDE don't show this method on hint. – r1se Mar 05 '14 at 13:58
  • I'm already close acceptor: if(stop == -1) {acc->close(); kill(); Application->Terminate();} – r1se Mar 05 '14 at 14:18
  • @user2393500 ok, so what's the problem exactly? What's wrong with the behavior that you observe? – Igor R. Mar 05 '14 at 14:45
  • Application don't terminate, i mean exe file stay working, and io-service creating again. Why he created new service, after i'm stopped him. – r1se Mar 05 '14 at 15:01
  • 1
    @user2393500 I guess the problem is in some other place in your code. Try and debug it in the debugger - set breakpoints, step into the code etc. – Igor R. Mar 05 '14 at 15:46
  • on debug, i'am stopped on run method for service, but how he started if i stop him? – r1se Mar 06 '14 at 08:47