Posted By


liouys on 03/20/11

Tagged


Statistics


Viewed 1045 times
Favorited by 0 user(s)

boost.asio异步重连


/ Published in: C++
Save to your folder(s)



Copy this code and paste it in your HTML
  1. //
  2. // async_client.cpp
  3. // ~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9.  
  10. #include <iostream>
  11. #include <istream>
  12. #include <ostream>
  13. #include <string>
  14. #include <boost/function.hpp>
  15. #include <boost/thread/once.hpp>
  16. #include <boost/thread.hpp>
  17. #include <boost/asio.hpp>
  18. #include <boost/bind.hpp>
  19.  
  20. using boost::asio::ip::tcp;
  21.  
  22. class client
  23. {
  24. public:
  25. typedef boost::function<void(client&)> on_complete_callback;
  26.  
  27. public:
  28. client(boost::asio::io_service& io_service)
  29. : resolver_(io_service)
  30. , socket_(io_service)
  31. , io_service_(io_service)
  32. {
  33. }
  34.  
  35. ~client()
  36. {
  37. io_thread_.join();
  38. }
  39.  
  40. void navigate(const std::string& server, const std::string& path)
  41. {
  42. if (socket_.is_open()) {
  43. boost::system::error_code ignored_ec;
  44. socket_.close(ignored_ec);
  45. }
  46. std::ostream request_stream(&request_);
  47. request_stream << "GET " << path << " HTTP/1.0
  48. ";
  49. request_stream << "Host: " << server << "
  50. ";
  51. request_stream << "Accept: */*
  52. ";
  53. request_stream << "Connection: close
  54.  
  55. ";
  56.  
  57. tcp::resolver::query query(server, "http");
  58. resolver_.async_resolve(query,
  59. boost::bind(&client::handle_resolve, this,
  60. boost::asio::placeholders::error,
  61. boost::asio::placeholders::iterator));
  62. io_thread_.swap(boost::thread(boost::bind(&client::io_service_run, this)));
  63. }
  64.  
  65. void regiseter_complete_callback(on_complete_callback callback)
  66. {
  67. on_complete_callback_ = callback;
  68. }
  69.  
  70. void close_socket()
  71. {
  72. boost::system::error_code ignored_ec;
  73. socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
  74. socket_.close(ignored_ec);
  75. }
  76.  
  77. void io_service_run()
  78. {
  79. boost::mutex::scoped_try_lock try_lock(io_mutex_);
  80. if (!try_lock) {
  81. return ;
  82. }
  83.  
  84. io_service_.run();
  85. io_service_.reset();
  86. }
  87.  
  88. private:
  89. void handle_resolve(const boost::system::error_code& err,
  90. tcp::resolver::iterator endpoint_iterator)
  91. {
  92. if (!err)
  93. {
  94. // Attempt a connection to the first endpoint in the list. Each endpoint
  95. // will be tried until we successfully establish a connection.
  96. tcp::endpoint endpoint = *endpoint_iterator;
  97. socket_.async_connect(endpoint,
  98. boost::bind(&client::handle_connect, this,
  99. boost::asio::placeholders::error, ++endpoint_iterator));
  100. }
  101. else
  102. {
  103. std::cout << "Error: " << err.message() << "\n";
  104. }
  105. }
  106.  
  107. void handle_connect(const boost::system::error_code& err,
  108. tcp::resolver::iterator endpoint_iterator)
  109. {
  110. if (!err)
  111. {
  112. // The connection was successful. Send the request.
  113. boost::asio::async_write(socket_, request_,
  114. boost::bind(&client::handle_write_request, this,
  115. boost::asio::placeholders::error));
  116. }
  117. else if (endpoint_iterator != tcp::resolver::iterator())
  118. {
  119. // The connection failed. Try the next endpoint in the list.
  120. socket_.close();
  121. tcp::endpoint endpoint = *endpoint_iterator;
  122. socket_.async_connect(endpoint,
  123. boost::bind(&client::handle_connect, this,
  124. boost::asio::placeholders::error, ++endpoint_iterator));
  125. }
  126. else
  127. {
  128. std::cout << "Error: " << err.message() << "\n";
  129. }
  130. }
  131.  
  132. void handle_write_request(const boost::system::error_code& err)
  133. {
  134. if (!err)
  135. {
  136. // Read the response status line. The response_ streambuf will
  137. // automatically grow to accommodate the entire line. The growth may be
  138. // limited by passing a maximum size to the streambuf constructor.
  139. boost::asio::async_read_until(socket_, response_, "
  140. ",
  141. boost::bind(&client::handle_read_status_line, this,
  142. boost::asio::placeholders::error));
  143. }
  144. else
  145. {
  146. std::cout << "Error: " << err.message() << "\n";
  147. }
  148. }
  149.  
  150. void handle_read_status_line(const boost::system::error_code& err)
  151. {
  152. if (!err)
  153. {
  154. // Check that response is OK.
  155. std::istream response_stream(&response_);
  156. std::string http_version;
  157. response_stream >> http_version;
  158. unsigned int status_code;
  159. response_stream >> status_code;
  160. std::string status_message;
  161. std::getline(response_stream, status_message);
  162. if (!response_stream || http_version.substr(0, 5) != "HTTP/")
  163. {
  164. std::cout << "Invalid response\n";
  165. return;
  166. }
  167. if (status_code != 200)
  168. {
  169. std::cout << "Response returned with status code ";
  170. std::cout << status_code << "\n";
  171. return;
  172. }
  173.  
  174. // Read the response headers, which are terminated by a blank line.
  175. boost::asio::async_read_until(socket_, response_, "
  176.  
  177. ",
  178. boost::bind(&client::handle_read_headers, this,
  179. boost::asio::placeholders::error));
  180. }
  181. else
  182. {
  183. std::cout << "Error: " << err << "\n";
  184. }
  185. }
  186.  
  187. void handle_read_headers(const boost::system::error_code& err)
  188. {
  189. if (!err)
  190. {
  191. // Process the response headers.
  192. std::istream response_stream(&response_);
  193. std::string header;
  194. while (std::getline(response_stream, header) && header != "\r")
  195. std::cout << header << "\n";
  196. std::cout << "\n";
  197.  
  198. // Write whatever content we already have to output.
  199. if (response_.size() > 0)
  200. std::cout << &response_;
  201.  
  202. // Start reading remaining data until EOF.
  203. boost::asio::async_read(socket_, response_,
  204. boost::asio::transfer_at_least(1),
  205. boost::bind(&client::handle_read_content, this,
  206. boost::asio::placeholders::error));
  207. }
  208. else
  209. {
  210. std::cout << "Error: " << err << "\n";
  211. }
  212. }
  213.  
  214. void handle_read_content(const boost::system::error_code& err)
  215. {
  216. if (!err)
  217. {
  218. // Write all of the data that has been read so far.
  219. std::cout << &response_;
  220.  
  221. // Continue reading remaining data until EOF.
  222. boost::asio::async_read(socket_, response_,
  223. boost::asio::transfer_at_least(1),
  224. boost::bind(&client::handle_read_content, this,
  225. boost::asio::placeholders::error));
  226. }
  227. else if (err != boost::asio::error::eof)
  228. {
  229. std::cout << "Error: " << err << "\n";
  230. }
  231. else
  232. {
  233. on_complete_callback_(*this);
  234. }
  235. }
  236.  
  237. tcp::resolver resolver_;
  238. tcp::socket socket_;
  239. boost::asio::streambuf request_;
  240. boost::asio::streambuf response_;
  241. boost::asio::io_service& io_service_;
  242. boost::thread io_thread_;
  243. boost::mutex io_mutex_;
  244. on_complete_callback on_complete_callback_;
  245. };
  246.  
  247. void complete(client& cli)
  248. {
  249.  
  250. }
  251.  
  252. int main(int argc, char* argv[])
  253. {
  254. try
  255. {
  256. if (argc != 3)
  257. {
  258. std::cout << "Usage: async_client <server> <path>\n";
  259. std::cout << "Example:\n";
  260. std::cout << " async_client www.boost.org /LICENSE_1_0.txt\n";
  261. return 1;
  262. }
  263.  
  264. boost::asio::io_service io_service;
  265. client cli(io_service);
  266.  
  267. cli.regiseter_complete_callback(boost::bind(&complete, boost::ref<client>(cli)));
  268. cli.navigate(argv[1], argv[2]);
  269.  
  270.  
  271. std::string in;
  272.  
  273. std::cout << "type 'exit' to exit.\nprompt # ";
  274.  
  275. for (;;)
  276. {
  277. char c = getchar();
  278. if (c == '\n' || c == EOF )
  279. {
  280.  
  281. if (in == "exit")
  282. {
  283. io_service.post(boost::bind(&client::close_socket, &cli));
  284. break;
  285. }
  286. else if (in == "r")
  287. {
  288. cli.navigate(argv[1], argv[2]);
  289. }
  290. else if(in != "")
  291. {
  292. system(in.c_str()); // std::cout << "Bad command ! \n";
  293. }
  294.  
  295. std::cout << "prompt # ";
  296. in = "";
  297. }
  298. else
  299. {
  300. in += c;
  301. }
  302. }
  303. }
  304. catch (std::exception& e)
  305. {
  306. std::cout << "Exception: " << e.what() << "\n";
  307. }
  308.  
  309. return 0;
  310. }

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.