00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifndef _ASYNC_CLIENT_H_
00028 #define _ASYNC_CLIENT_H_
00029
00035 #include <iostream>
00036 #include <istream>
00037 #include <ostream>
00038 #include <string>
00039 #include <boost/asio.hpp>
00040 #include <boost/bind.hpp>
00041 #include <boost/date_time/posix_time/posix_time.hpp>
00042 #include <boost/signal.hpp>
00043 #include <boost/thread/thread.hpp>
00044
00045 using boost::asio::ip::tcp;
00046
00047 using namespace std;
00048
00054 class AsyncClient
00055 {
00056 public:
00063 AsyncClient(boost::asio::io_service& io_service,const std::string& server, const std::string& port,std::string delimiter=std::string("\n")):
00064 delimiter_(delimiter),
00065 server_ip_(server),
00066 server_port_(port),
00067 query_(server_ip_,server_port_),
00068 resolver_(io_service),
00069 socket_(io_service)
00070 {
00071 attempting_connection_=false;
00072 is_connected_=false;
00073 error_ = boost::asio::error::not_connected;
00074
00075 startConnection();
00076 }
00077
00083 ~AsyncClient()
00084 {
00085 socket_.close();
00086 }
00087
00094 void startConnection()
00095 {
00096 if(attempting_connection_)
00097 return;
00098
00099 try
00100 {
00101 socket_.close();
00102 }catch(std::exception& e)
00103 {
00104
00105 }
00106
00107 attempting_connection_=true;
00108
00109
00110
00111 is_connected_=false;
00112
00113
00114 boost::this_thread::sleep(boost::posix_time::milliseconds(50));
00115
00116
00117 resolver_.async_resolve(query_,boost::bind(&AsyncClient::handleResolve, this,boost::asio::placeholders::error,boost::asio::placeholders::iterator));
00118 }
00119
00125 bool isConnected(void)
00126 {
00127 return is_connected_;
00128 }
00129
00133 void close(void)
00134 {
00135 socket_.close();
00136 error_ = boost::asio::error::not_connected;
00137 is_connected_ = false;
00138 }
00139
00143 void reconnect(void)
00144 {
00145
00146 startConnection();
00147 }
00148
00156 void write(std::string message)
00157 {
00158 if(!is_connected_)
00159 throw boost::system::system_error(boost::asio::error::not_connected);
00160
00161 std::ostream request_stream(&request_);
00162 request_stream << message;
00163 boost::asio::async_write(socket_,request_,boost::bind(&AsyncClient::writeRequestHandler, this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
00164 }
00165
00167 boost::signal<void (std::string)> readHandler;
00169 boost::signal<void (void)> writeHandler;
00171 boost::signal<void (void)> connectHandler;
00173 boost::system::error_code error_;
00174
00175 private:
00185 void writeRequestHandler(const boost::system::error_code& err,std::size_t bytes_transferred)
00186 {
00187 if(err)
00188 {
00189
00190 is_connected_=false;
00191
00192 error_=err;
00193
00194 attempting_connection_=false;
00195
00196
00197 startConnection();
00198
00199 return;
00200 }
00201
00202 writeHandler();
00203 }
00204
00214 void handleResolve(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator)
00215 {
00216
00217 if(err)
00218 {
00219
00220 is_connected_=false;
00221
00222 error_=err;
00223
00224 attempting_connection_=false;
00225
00226
00227 startConnection();
00228
00229 return;
00230 }
00231
00232
00233
00234
00235 tcp::endpoint endpoint = *endpoint_iterator;
00236
00237
00238 socket_.async_connect(endpoint,boost::bind(&AsyncClient::handleConnect, this,boost::asio::placeholders::error, ++endpoint_iterator));
00239 }
00240
00250 void handleConnect(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator)
00251 {
00252
00253 if(is_connected_)
00254 return;
00255
00256
00257 if (!err)
00258 {
00259
00260 startRead();
00261
00262
00263 error_=err;
00264
00265
00266 is_connected_=true;
00267
00268 attempting_connection_=false;
00269
00270
00271 connectHandler();
00272 }
00273 else if (endpoint_iterator != tcp::resolver::iterator())
00274 {
00275
00276
00277
00278 socket_.close();
00279
00280
00281 tcp::endpoint endpoint = *endpoint_iterator;
00282
00283 socket_.async_connect(endpoint,boost::bind(&AsyncClient::handleConnect,this,boost::asio::placeholders::error, ++endpoint_iterator));
00284 }
00285 else
00286 {
00287
00288
00289
00290 is_connected_=false;
00291
00292 attempting_connection_=false;
00293
00294
00295 error_=err;
00296
00297 if(error_ == boost::asio::error::operation_aborted || error_ == boost::asio::error::already_started)
00298 error_=boost::asio::error::host_unreachable;
00299
00300
00301 startConnection();
00302 }
00303 }
00304
00311 void startRead(void)
00312 {
00313
00314 boost::asio::async_read_until(socket_,response_,delimiter_,boost::bind(&AsyncClient::handleRead,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
00315 }
00316
00327 void handleRead(const boost::system::error_code& err, std::size_t bytes_transferred)
00328 {
00329
00330 if(err)
00331 {
00332
00333 is_connected_=false;
00334
00335
00336 error_ = err;
00337
00338 attempting_connection_=false;
00339
00340
00341 startConnection();
00342
00343 return;
00344 }
00345
00346
00347 std::istream response_stream(&response_);
00348
00349 std::string line;
00350
00351 std::getline(response_stream, line);
00352
00353
00354 readHandler(line);
00355
00356
00357 startRead();
00358 }
00359
00361 std::string delimiter_;
00362
00364 bool is_connected_;
00365
00367 bool attempting_connection_;
00368
00370 std::string server_ip_;
00372 std::string server_port_;
00373
00375 tcp::resolver::query query_;
00376
00378 tcp::resolver resolver_;
00380 tcp::socket socket_;
00382 boost::asio::streambuf request_;
00384 boost::asio::streambuf response_;
00385 };
00386
00387 #endif