I´m trying to build a synchronous FTP client code with timeout using a thread as the timeout control. The thread will be started on every transaction and will close the socket in case of timeout - that will force the syncronous call to return with error.
So here is my 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 now = 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 to 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 to connect or END to 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 to server.");
}
std::cout << "Connected to " << 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 simply cannot compile this code, as boost is showing me the 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> with
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> with
1> [
1> IoObjectService=boost::asio::stream_socket_service<boost::asio::ip::tcp>
1> ]
1> This diagnostic occurred in the compiler generated function 'boost::asio::basic_socket<Protocol,SocketService>::basic_socket(const boost::asio::basic_socket<Protocol,SocketService> &)'
1> with
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, I wanna know about 2 things:
a) What am I doing wrong in the code ?
b) Will this approach of closing the socket on a parallel thread work for timing out the socket ? Please fell free to comment it.
Thanks for helping.