/* * Listen on a given port and recieve files sent to that port. * * 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 _WIN32_WINNT 0x0501 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include //! tcp_connection /*! * We will use shared_ptr and enable_shared_from_this because we want to keep the * tcp_connection object alive as long as there is an operation that refers to it. * * The received data looks like this: \n * */ class tcp_connection : public boost::enable_shared_from_this { public: typedef boost::shared_ptr pointer; static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); } boost::asio::ip::tcp::socket& socket() { return socket_; } void start() { boost::asio::async_read(socket_, boost::asio::buffer(buffer_), boost::bind(&tcp_connection::read_handler, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) { bytes_ += bytes_transferred; if (!ec || ec == boost::asio::error::eof) { std::string data(buffer_.data(), bytes_transferred); if (filename_.empty()) { std::istringstream iss(data); std::getline(iss, filename_); file_ = data; file_.erase(0, filename_.size() + 1); filename_ = boost::filesystem::path(filename_).filename(); // Ooen the file. ofs_.open(filename_.c_str(), std::ios::out | std::ios::binary); if (ofs_) { ofs_ << file_; ofs_.flush(); } else { std::cerr << filename_ << " couldn't be created" << std::endl; boost::throw_exception( boost::filesystem::wfilesystem_error( "file creation error", boost::system::error_code( boost::system::posix::invalid_argument, boost::system::system_category ) ) ); } } else { ofs_ << data; ofs_.flush(); } if (!ec) boost::asio::async_read(socket_, boost::asio::buffer(buffer_), boost::bind(&tcp_connection::read_handler, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); else { // Bytes received = filename_.size()+1+file_size_ std::cout << filename_ << " received from " << socket_.remote_endpoint() << " " << bytes_ << " bytes." << std::endl; } } else std::cerr << "read_handler error: " << ec << " - " << ec.message() << std::endl; } private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service) , bytes_(0) { } std::string filename_; std::string file_; boost::asio::ip::tcp::socket socket_; boost::array buffer_; size_t bytes_; std::ofstream ofs_; }; class tcp_server { public: //! An acceptor is initialised in the constructor to listen on the chosen port. tcp_server(boost::asio::io_service& io_service, unsigned int &port) : acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) { start_accept(); } private: //! Create a socket and initiate an asynchronous accept operation to wait for a new connection. void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.io_service()); acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error)); } /*! * This is called when the asynchronous accept operation initiated by start_accept() finishes. * It services the client request, and then calls start_accept() to initiate the next accept operation. */ void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); start_accept(); } else { throw(error); } } boost::asio::ip::tcp::acceptor acceptor_; }; class setup_server { public: setup_server(std::string const & port) { boost::system::error_code ec; std::cout << "Host: " << boost::asio::ip::host_name() << std::endl; std::cout << "Listening on port: " << port << std::endl; boost::asio::ip::tcp::resolver::query query(boost::asio::ip::host_name(), port); boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::iterator it = resolver.resolve(query,ec); if (ec) { throw(ec); } // Look at what connections we have. boost::asio::ip::tcp::resolver::iterator end; while (it != end) { std::cout << it->endpoint().address() << std::endl; ++it; } unsigned int p = boost::lexical_cast(port); tcp_server server(io_service,p); io_service.run(); } private: }; int main(int argc, const char *argv[]) { if (argc < 2) { std::cerr << "You must provide the port to listen on." << 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; return EXIT_SUCCESS; } try { setup_server server_setup(argv[1]); } catch (boost::system::error_code ec) { std::cerr << "error: " << ec << " - " << ec.message() << std::endl; return EXIT_FAILURE; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }