c++ - Boost::Asio synchronous client with timeout -
i´m trying build synchronous ftp client code timeout using thread timeout control. thread started on every transaction , close socket in case of timeout - force syncronous call return error.
so here code:
#include <cstdlib> #include <cstring> #include <iostream> #include <thread> #include <chrono> #include <boost/asio.hpp> #define timeout_seconds 5 #define max_message_size 4096 using boost::asio::ip::tcp; enum { max_length = 1024 }; bool timeron; void socket_timer(tcp::socket& s, int seconds) { std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); while (timeron) { std::chrono::system_clock::time_point = std::chrono::system_clock::now(); auto interval = std::chrono::duration_cast<std::chrono::seconds>(now - start).count(); if (interval > seconds) break; std::this_thread::sleep_for(std::chrono::milliseconds(10)); // not run in 100% cpu } if (timeron) s.close(); } void start_timer(int seconds, tcp::socket& s) { timeron = true; std::thread t(socket_timer, s, seconds); t.detach(); } void stop_timer() { timeron = false; } int main(int argc, char* argv[]) { std::string address; while(address != "end") { try { boost::asio::io_service io_service; std::cout << "enter ftp server address connect or end finish: " << std::endl; std::cin >> address; if (address == "end") break; tcp::socket s(io_service); tcp::resolver resolver(io_service); boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(address), 21); start_timer(timeout_seconds, s); boost::system::error_code ec; s.connect(endpoint, ec); stop_timer(); if (ec) { throw std::runtime_error("error connecting server."); } std::cout << "connected " << s.remote_endpoint().address().to_string() << std::endl; char reply[max_length]; start_timer(timeout_seconds, s); size_t bytes = s.receive(boost::asio::buffer(reply, max_message_size), 0, ec); stop_timer(); if (ec) { throw std::runtime_error("error receiving message."); } std::cout << "received message is: "; std::cout.write(reply, bytes); std::cout << "\n"; std::cout << "enter message: "; char request[max_length]; std::cin.getline(request, max_length); size_t request_length = std::strlen(request); start_timer(timeout_seconds, s); boost::asio::write(s, boost::asio::buffer(request, request_length)); stop_timer(); if (ec) { throw std::runtime_error("error sending message."); } } catch (std::exception& e) { std::cerr << "communications error." << "\n"; std::cerr << "exception: " << e.what() << "\n"; } } return 0; }
i cannot compile code, boost showing me following error:
1>------ build started: project: testasio, configuration: debug win32 ------ 1> main.cpp 1>c:\boost_1_60\boost\asio\basic_socket.hpp(1513): error c2248: 'boost::asio::basic_io_object<ioobjectservice>::basic_io_object' : cannot access private member declared in class 'boost::asio::basic_io_object<ioobjectservice>' 1> 1> [ 1> ioobjectservice=boost::asio::stream_socket_service<boost::asio::ip::tcp> 1> ] 1> c:\boost_1_60\boost\asio\basic_io_object.hpp(230) : see declaration of 'boost::asio::basic_io_object<ioobjectservice>::basic_io_object' 1> 1> [ 1> ioobjectservice=boost::asio::stream_socket_service<boost::asio::ip::tcp> 1> ] 1> diagnostic occurred in compiler generated function 'boost::asio::basic_socket<protocol,socketservice>::basic_socket(const boost::asio::basic_socket<protocol,socketservice> &)' 1> 1> [ 1> protocol=boost::asio::ip::tcp, 1> socketservice=boost::asio::stream_socket_service<boost::asio::ip::tcp> 1> ] ========== build: 0 succeeded, 1 failed, 9 up-to-date, 0 skipped ==========
so, wanna know 2 things:
a) doing wrong in code ?
b) approach of closing socket on parallel thread work timing out socket ? please fell free comment it.
thanks helping.
i've made helper facility asio async operation "synchronously" timeout here, await_operation
:
you should able adapt pattern sample.
demo
it took while since wanted test ftp server.
notes:
- you didn't resolve address (effectively requiring user type in ip address)
- you didn't make sure commands closed newline
- you didn't handle kind of input error
fixing these things and using await_operation
you'd this:
#include <cstdlib> #include <cstring> #include <iostream> #include <thread> #include <chrono> #include <boost/asio.hpp> #include <boost/asio/high_resolution_timer.hpp> #define timeout std::chrono::seconds(5) #define max_message_size 4096 using boost::asio::ip::tcp; enum { max_length = 2048 }; struct service { using error_code = boost::system::error_code; template<typename allowtime, typename cancel> void await_operation_ex(allowtime const& deadline_or_duration, cancel&& cancel) { using namespace boost::asio; ioservice.reset(); { high_resolution_timer tm(ioservice, deadline_or_duration); tm.async_wait([&cancel](error_code ec) { if (ec != error::operation_aborted) std::forward<cancel>(cancel)(); }); ioservice.run_one(); } ioservice.run(); } template<typename allowtime, typename serviceobject> void await_operation(allowtime const& deadline_or_duration, serviceobject& so) { return await_operation_ex(deadline_or_duration, [&so]{ so.cancel(); }); } boost::asio::io_service ioservice; }; int main() { while(true) { try { service service; std::cout << "enter ftp server address connect or end finish: " << std::endl; std::string address; if (std::cin >> address) { if (address == "end") break; } else { if (std::cin.eof()) break; std::cerr << "invalid input ignored\n"; std::cin.clear(); std::cin.ignore(1024, '\n'); continue; } tcp::socket s(service.ioservice); tcp::resolver resolver(service.ioservice); boost::asio::async_connect(s, resolver.resolve({address, "21"}), [](boost::system::error_code ec, tcp::resolver::iterator it) { if (ec) throw std::runtime_error("error connecting server: " + ec.message()); std::cout << "connected " << it->endpoint() << std::endl; }); service.await_operation_ex(timeout, [&]{ throw std::runtime_error("error connecting server: timeout\n"); }); auto receive = [&] { boost::asio::streambuf sb; size_t bytes; boost::asio::async_read_until(s, sb, '\n', [&](boost::system::error_code ec, size_t bytes_transferred) { if (ec) throw std::runtime_error("error receiving message: " + ec.message()); bytes = bytes_transferred; std::cout << "received message is: " << &sb; }); service.await_operation(timeout, s); return bytes; }; receive(); // banner auto send = [&](std::string cmd) { boost::asio::async_write(s, boost::asio::buffer(cmd), [](boost::system::error_code ec, size_t /*bytes_transferred*/) { if (ec) throw std::runtime_error("error sending message: " + ec.message()); }); service.await_operation(timeout, s); }; auto ftp_command = [&](std::string cmd) { send(cmd + "\r\n"); receive(); // response }; //ftp_command("user bob"); //ftp_command("pass hello"); while (true) { std::cout << "enter command: "; std::string request; if (!std::getline(std::cin, request)) break; ftp_command(request); } } catch (std::exception const& e) { std::cerr << "communications error " << e.what() << "\n"; } } return 0; }
which, in test run, prints e.g.:
Comments
Post a Comment