2016-03-22 9 views
0

次のコードを使用して、非同期クライアントをコーディングしようとしています。Asio:非同期クライアントが削除されないようにしますか?

main()には、実行がスコープを離れるため、try-catchブロックでClientが削除されるという問題があります。

私はwhile(true)を追加するなど、この問題の解決策を考え出しましたが、私はこの方法が嫌いです。また、私はgetchar()を好まない。

コールの非同期性のため、connect()loop()の両方がただちに戻ります。

どうすればこの問題を解決できますか?

#include <iostream> 
#include <thread> 
#include <string> 

#include <boost\asio.hpp> 
#include <Windows.h> 

#define DELIM "\r\n" 

using namespace boost; 


class Client { 
public: 
    Client(const std::string& raw_ip_address, unsigned short port_num) : 
     m_ep(asio::ip::address::from_string(raw_ip_address), port_num), m_sock(m_ios) 
    { 
     m_work.reset(new asio::io_service::work(m_ios)); 
     m_thread.reset(new std::thread([this]() { 
      m_ios.run(); 
     })); 

     m_sock.open(m_ep.protocol()); 
    } 

    void connect() 
    { 
     m_sock.async_connect(m_ep, [this](const system::error_code& ec) 
     { 
      if (ec != 0) { 
       std::cout << "async_connect() error: " << ec.message() << " (" << ec.value() << ") " << std::endl; 
       return; 
      } 

      std::cout << "Connection to server has been established." << std::endl; 
     }); 
    } 

    void loop() 
    { 
     std::thread t = std::thread([this]() 
     { 
      recv(); 
     }); 

     t.join(); 
    } 

    void recv() 
    { 
     asio::async_read_until(m_sock, buf, DELIM, [this](const system::error_code& ec, std::size_t bytes_transferred) 
     { 
      if (ec != 0) { 
       std::cout << "async_read_until() error: " << ec.message() << " (" << ec.value() << ") " << std::endl; 
       return; 
      } 

      std::istream is(&buf); 
      std::string req; 
      std::getline(is, req, '\r'); 
      is.get(); // discard newline 

      std::cout << "Received: " << req << std::endl; 

      if (req == "alive") { 
       recv(); 
      } 
      else if (req == "close") { 
       close(); 
       return; 
      } 
      else { 
       send(req + DELIM); 
      } 
     }); 
    } 

    void send(std::string resp) 
    { 
     auto s = std::make_shared<std::string>(resp); 
     asio::async_write(m_sock, asio::buffer(*s), [this, s](const system::error_code& ec, std::size_t bytes_transferred) 
     { 
      if (ec != 0) { 
       std::cout << "async_write() error: " << ec.message() << " (" << ec.value() << ") " << std::endl; 
       return; 
      } 
      else { 
       recv(); 
      } 
     }); 
    } 

    void close() 
    { 
     m_sock.close(); 
     m_work.reset(); 
     m_thread->join(); 
    } 

private: 
    asio::io_service m_ios; 
    asio::ip::tcp::endpoint m_ep; 
    asio::ip::tcp::socket m_sock; 
    std::unique_ptr<asio::io_service::work> m_work; 
    std::unique_ptr<std::thread> m_thread; 

    asio::streambuf buf; 
}; 

int main() 
{ 
    const std::string raw_ip_address = "127.0.0.1"; 
    const unsigned short port_num = 8001; 

    try { 
     Client client(raw_ip_address, port_num); 
     client.connect(); 
     client.loop(); 
    } 
    catch (system::system_error &err) { 
     std::cout << "main() error: " << err.what() << " (" << err.code() << ") " << std::endl; 
     return err.code().value(); 
    } 
    return 0; 
} 

答えて

0

あなたはやる)(メインに続いて(ハンドラ) http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/io_service/post.html

ポストを経由してio_serviceするような任意の関数を投稿することができます:

while (!exit) { 
    io_service.run_one(); 
} 

するか、:: io_serviceを呼び出すrun_oneかio_service ::メインで実行する

+0

PS。 io_serviceに実行のためのハンドラやワーカーがない場合io_service :: run()はcontrollを返します。 –

1

あなたはasioの仕組みを本当に理解していません。通常、メインスレッド(複数可)に、あなたは(すべての非同期イベントを処理するた。)io_service::run()を呼び出します

を、Clientの寿命を確保shared_ptr<>を使用して、この共有ポインタがハンドラで使用されていることを確認するには。たとえば...

io_service service; 

{ 
    // Create the client - outside of this scope, asio will manage 
    // the life time of the client 
    auto client = make_shared<Client>(service); 
    client->connect(); // setup the connect operation.. 
} 
// Now run the io service event loop - this will block until there are no more 
// events to handle 
service.run(); 

は今、あなたはあなたのClientコードをリファクタリングする必要があります - 必要はありません

class Client : public std::enable_shared_from_this<Client> { 

Client(io_service& service): socket_(service) ... 
{ } 

void connect() { 
    // By copying the shared ptr to the lambda, the life time of 
    // Client is guaranteed 
    socket_.async_connect(endpoint_, [self = this->shared_from_this()](auto ec) 
    { 
     if (ec) { 
     return; 
     } 

     // Read 
     self->read(self); 
    }); 
} 

void read(shared_ptr<Client> self) { 
    // By copying the shared ptr to the lambda, the life time of 
    // Client is guaranteed 
    asio::async_read_until(socket_, buffer_, DELIM, [self](auto ec, auto size) 
    { 
    if (ec) { 
     return; 
    } 
    // Handle the data 
    // Setup the next read operation 
    self->read(self) 
    }); 
} 
}; 

あなたは、読み出し動作のためのスレッドを持っています。それは1つの非同期読み取り操作を登録し、直ちに戻る。ソケットを読み続けるために新しい読み取り操作を登録する必要があります(私がスケッチしたように)

関連する問題