/* * Send files to a receiver that listens on a given port for the file * and its contents. * * This is an example program so feel free to adapt it for your own use. * * Many thanks to all the people who contributed to this. * In particular, Rahul who provided * some code to start with and Cliff Green * for his comments. * * If anyone can improve on this example please send me a copy, * also post it to the boost users group * * Thankyou, Andrew Maclean * 2009-02-04 */ #ifdef _WIN32 # define NOMINMAX # define _WIN32_WINNT 0x0501 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include // This is a list of files that have to be sent. typedef std::vector FnList; typedef FnList::iterator FnListIt; typedef FnList::const_iterator FnListCIt; // The list of files. FnList FileNameList; //! Send a file to the waiting server on another machine. /*! * This class takes an io_service, the ip address of the server to where the * file will be sent, the port, and the file name and sends the file out on the port. * The file name is sent first and then the contents of the file are sent. * So the transmitted data looks like this: \n * * If you have used the name of the server instead of the ip, you can retrieve the * ip of the server for subsequent use, thereby avoiding the dns lookup. * * The buffer is a boost array of 4096 characters, you can change the size of this array if you want. */ class tcp_server { public: tcp_server(boost::asio::io_service & io_service, std::string const & address, std::string const & port, std::string const & filename) : io_service_(&io_service) , socket_(io_service) , sent_(0) , filename_(filename) , file_size_(0) , bytes_(0) { boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query(address, port); boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); boost::asio::ip::tcp::resolver::iterator end; boost::system::error_code error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) { socket_.close(); socket_.connect(*endpoint_iterator++, error); } if (error) throw boost::system::system_error(error); // Get the name of the endpoint. endpoint_iterator = resolver.resolve(socket_.remote_endpoint()); remote_endpoint_name_ = endpoint_iterator->host_name(); remote_endpoint_ip_ = socket_.remote_endpoint().address().to_string(); std::cout << "Connecting to " << remote_endpoint_name_ << " " << socket_.remote_endpoint() << std::endl; ifs_.open(filename_.c_str(), std::ios::in | std::ios::binary); if ( ifs_ ) { ifs_.seekg(0,std::ios::end); file_size_ = ifs_.tellg(); ifs_.seekg(0,std::ios::beg); connect_handler(error); } else { std::cerr << filename_ << " not found." << std::endl; } } std::string get_remote_endpoint_ip() const { return remote_endpoint_ip_; } std::string get_remote_endpoint_name() const { return remote_endpoint_name_; } private: void connect_handler(const boost::system::error_code& error) { if (!error) { std::cout << "Transferring " << filename_ << std::flush; // Put the file name in the buffer std::memcpy(buffer_.c_array(), filename_.c_str(), filename_.size()); buffer_[filename_.size()] = '\n'; // and start the writing process. boost::asio::async_write(socket_, boost::asio::buffer(buffer_, filename_.size() + 1), boost::bind(&tcp_server::write_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else std::cerr << "connect_handler error: " << error << " - " << error.message() << std::endl; } void write_handler(const boost::system::error_code& error, std::size_t bytes_transferred) { bytes_ += bytes_transferred; if (!error) { if (sent_ < file_size_) { std::size_t size = std::min(buffer_.size(), file_size_ - sent_); //std::cout << "file position: " << ifs_.tellg() << std::endl; ifs_.read(buffer_.c_array(), size); sent_ += size; boost::asio::async_write(socket_, boost::asio::buffer(buffer_, size), boost::bind(&tcp_server::write_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { // Bytes transferred = filename_.size()+1+file_size_ std::cout << " done, bytes transferred: " << bytes_ << std::endl; } } else std::cerr << "write_handler error: " << error << " - " << error.message() << std::endl; } boost::asio::io_service *io_service_; boost::asio::ip::tcp::socket socket_; boost::asio::ip::tcp::endpoint endpoint_; boost::array buffer_; std::size_t sent_; std::string filename_; std::ifstream ifs_; size_t file_size_; size_t bytes_; std::string remote_endpoint_ip_; std::string remote_endpoint_name_; }; int main(int argc, const char *argv[]) { if (argc < 4) { std::cerr << "You must provide the name or IP address of the machine " << "\nyou are sending to, along with the port and a list of the files to send." << std::endl; std::cerr << "Make sure that the port is not blocked by the firewall." << std::endl; std::cerr << "Syntax: " << std::endl; std::cerr << argv[0] << " ... " << std::endl; std::cerr << "For example:" << std::endl; std::cerr << argv[0] << " myserver.com 9999 file1.txt \"Another file2.txt\"" << std::endl; std::cerr << argv[0] << " myserver.com 9999 file1.txt \"Another file2.txt\"" << std::endl; return EXIT_FAILURE; } // Gather up the file names. for ( int i = 3; i < argc; ++i ) { // Crude check for existence. std::ifstream ifs(argv[i], std::ios::in | std::ios::binary); if ( ifs ) { FileNameList.push_back(argv[i]); } else { std::cerr << argv[i] << " not found." << std::endl; } ifs.close(); } std::string remote_endpoint_ip = argv[1]; std::string remote_endpoint_name; // Process each file try { for ( FnListCIt p = FileNameList.begin(); p != FileNameList.end(); ++p ) { std::ifstream ifs(p->c_str(), std::ios::in | std::ios::binary); if (!ifs) { continue; } else { boost::asio::io_service io_service; // Send the file. tcp_server server(io_service,remote_endpoint_ip,argv[2],*p); if ( p == FileNameList.begin() ) { // If the end point name was used let us now use // the ip of the endpoint for subsequent transfers. // It is faster because there is no dns lookup. remote_endpoint_ip = server.get_remote_endpoint_ip(); remote_endpoint_name = server.get_remote_endpoint_name(); } io_service.run(); } } } catch (std::exception& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }