c++ - How to prevent ASIO based server from terminating -


i have been reading boost asio tutorials. far, understanding entire send , receive loop can iterated once. please have @ following simple code:

client.cpp:

#include <boost/asio.hpp> #include <boost/array.hpp> #include <iostream> #include <string>  boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::socket sock(io_service); boost::array<char, 4096> buffer;  void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) {   if (!ec)   {     std::cout << std::string(buffer.data(), bytes_transferred) << std::endl;     sock.async_read_some(boost::asio::buffer(buffer), read_handler);   } }  void connect_handler(const boost::system::error_code &ec) {   if (!ec)   {             sock.async_read_some(boost::asio::buffer(buffer), read_handler);   } }  void resolve_handler(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator it) {   if (!ec)   {     sock.async_connect(*it, connect_handler);   } }  int main() {   boost::asio::ip::tcp::resolver::query query("localhost", "2013");   resolver.async_resolve(query, resolve_handler);   io_service.run(); } 

the program resolves address, connects server , reads data, , ends when there no data. question: how can continue loop? mean, how can keep connection between client , server during entire lifetime of application server sends data whenever has send? tried break circle seams trapped inside io_service.run() same question holds in case of sever also:

server.cpp :

#include <boost/asio.hpp> #include <string>  boost::asio::io_service io_service; boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 2013); boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint); boost::asio::ip::tcp::socket sock(io_service); std::string data = "hello, world!";  void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) { }  void accept_handler(const boost::system::error_code &ec) {   if (!ec)   {     boost::asio::async_write(sock, boost::asio::buffer(data), write_handler);   } }  int main() {   acceptor.listen();   acceptor.async_accept(sock, accept_handler);   io_service.run(); } 

this example. in real application, may keep socket open , reuse other data exchanges(both read , write). how may that.

i value kind comments. if have references easy solutions addressing issue, appreciate if mention it. thank you

update (server sample code)

based on answer given below(update 2), wrote server code. please note code simplified (able compile&run though). note io_service never return coz waiting new connection. and how io_service.run never returns , runs ever. whenever want io_service.run return, make acceptor not accept anymore. please in 1 of many ways don't remember.(seriously, how in clean way? :) )

enjoy:

#include <boost/asio.hpp> #include <boost/thread.hpp> #include <string> #include <iostream> #include <vector> #include <time.h> boost::asio::io_service io_service; boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 2013); boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint); //boost::asio::ip::tcp::socket sock(io_service); std::string data = "hello, world!";  class observer; std::vector<observer*> observers;  class observer { public:     observer(boost::asio::ip::tcp::socket *socket_):socket_obs(socket_){}     void notify(std::string data)     {         std::cout << "notify called data[" << data << "]" << std::endl;         boost::asio::async_write(*socket_obs, boost::asio::buffer(data) , boost::bind(&observer::write_handler, this,boost::asio::placeholders::error));     }     void write_handler(const boost::system::error_code &ec)     {          if (!ec) //no error: done, wait next notification              return;          socket_obs->close(); //client error , exit read_handler          observers.erase(std::find(observers.begin(), observers.end(),this));          std::cout << "observer::write_handler  returns nothing written" << std::endl;     } private:         boost::asio::ip::tcp::socket *socket_obs; };   class server { public:      void creatsocketandaccept()      {           socket_ = new boost::asio::ip::tcp::socket(io_service);           observers.push_back(new observer(socket_));           acceptor.async_accept(*socket_,boost::bind(&server::handle_accept, this,boost::asio::placeholders::error));      }       server(boost::asio::io_service& io_service)       {           acceptor.listen();           creatsocketandaccept();       }        void handle_accept(const boost::system::error_code& e)       {           creatsocketandaccept();       } private:   boost::asio::ip::tcp::socket *socket_; };  class agent { public:     void update(std::string data)     {         if(!observers.empty())         { //          std::cout << "calling notify data[" << data << "]" << std::endl;             observers[0]->notify(data);         }     }  }; agent agent; void agentsim() {     int = 0;     sleep(10);//wait me start client     while(i++ < 10)     {         std::ostringstream out("");         out << data << ; //      std::cout << "calling update data[" << out.str() << "]" << std::endl;         agent.update(out.str());         sleep(1);     } } void run() {     io_service.run();     std::cout << "io_service returned" << std::endl; } int main() {     server server_(io_service);      boost::thread thread_1(agentsim);     boost::thread thread_2(run);     thread_2.join();     thread_1.join(); } 

you can simplify logic of asio based porgrams follows: each function calls async_x function provides handler. bit transitions between states of state machine, handlers states , async-calls transitions between states. exiting handler without calling async_* function transition end state. program "does" (sending data, receiving data, connecting sockets etc.) occurs during transitions.

if see way, client looks (only "good path", i.e. without errors):

<start>         --(resolve)----> resolve_handler resolve_handler --(connect)----> connect_handler connect_handler --(read data)--> read_handler read_handler    --(read data)--> read_handler 

your server loks this:

<start>         --(accept)-----> accept handler accept_handler  --(write data)-> write_handler write_handler   ---------------> <end> 

since write_handler not anything, makes transition end state, meaning ioservice::run returns. question is, want do, after data has been written socket? depending on that, have define corresponding transition, i.e. async-call want do.

update: comment see want wait next data ready i.e. next tick. transitions this:

write_handler   --(wait tick/data)--> dataready dataready       --(write data)----------> write_handler 

you see, introduces new state (handler), called dataready, call tick_handler or else. transition write_handler easy:

void dataready() {   // new data...   async_write(sock, buffer(data), write_handler); } 

the transition write_handler can simple async_wait on timer. if data come "outside" , don't know when ready, wait time, check if data there, , if not, wait more time:

write_handler    --(wait time)--> checkfordata checkfordata:no  --(wait time)--> checkfordata checkfordata:yes --(write data)------> write_handler 

or, in (pseudo)code:

void write_handler(const error_code &ec, size_t bytes_transferred) {   //...   async_wait(ticklenght, checkfordata); }  void checkfordata(/*insert wait handler signature here*/) {   if (dataisready())   {     async_write(sock, buffer(data), write_handler);   }   else   {     async_wait(shorttime, checkfordata):   } } 

update 2: according comment, have agent time management somehow (calling update every tick). here's how solve that:

  1. let agent have list of observers notified when there new data in update call.
  2. let each observer handle 1 client connection (socket).
  3. let server wait incomming connections, create observers them , register them agent.

i not firm in exact syntax of asio, handwavy pseudocode:

server:

void server::accept_handler() {     obs = new observer(socket);     agent.register(obs);     new socket; //observer takes care of old 1     async_accept(..., accept_handler); } 

agent:

void agent::update() {     if (newdataavailable())     {         (auto& obs : observers)         {              obs->notify(data);         }     } } 

observer:

void observer::notify(data) {     async_write(sock, data, write_handler); }  void observer::write_handler(error_code ec, ...) {      if (!ec) //no error: done, wait next notification          return;      //on error: close connection , unregister      agent.unregister(this);      socket.close(); //client error , exit read_handler } 

Comments

Popular posts from this blog

monitor web browser programmatically in Android? -

Shrink a YouTube video to responsive width -

wpf - PdfWriter.GetInstance throws System.NullReferenceException -