2014-04-04 48 views
3

我想通過TCP通過局域網傳輸一些文件,所以我寫了下面的代碼爲我的TX-部分:文件傳輸

void send_data(char * filename, char * dest) 
{ 
    try 
    { 
     boost::asio::io_service io_service; 
     char dest_t = *dest; 
     std::string adr = ip_adr_display[0] + ':' + boost::lexical_cast<std::string>(PORTNUM_TCP_IN); 
     std::cout << "Adress is: " << adr << " and file is: " << filename << '\n'; 
     if(debugmode) 
      debug_global << adr << '\n'; 
     std::string file = filename; 
     async_tcp_client client(io_service, adr, file); 
     io_service.run(); 
    } 
    catch(std::exception& e) 
    { 
    }; 
}; 

和RX-部分:

void rec_data(void) 
{ 
    try 
    { 
     std::cout << "Receiving data...\n"; 
     async_tcp_server *recv_file_tcp_server = new async_tcp_server(PORTNUM_TCP_IN); 
     if(debugmode) 
      debug_global << "Receiving...\n"; 
     delete recv_file_tcp_server; 
    } 
    catch(std::exception &e) 
    { 
    }; 
}; 

與以下服務器和客戶端代碼:(?爲什麼)

using boost::asio::ip::tcp; 
    class async_tcp_client 
    { 
    public: 
     async_tcp_client(boost::asio::io_service& io_service, const std::string& server, const std::string& path):resolver_(io_service), socket_(io_service) 
     { 
      size_t pos = server.find(':'); 
      if(pos==std::string::npos) 
       return; 
      std::string port_string = server.substr(pos+1); 
      std::string server_ip_or_host = server.substr(0,pos); 
      source_file.open(path.c_str(), std::ios_base::binary|std::ios_base::ate); 
      if(!source_file) 
      { 
       std::cout << "Failed to open " << path << std::endl; 
       return; 
      } 
      size_t file_size = source_file.tellg(); 
      source_file.seekg(0); 
      std::ostream request_stream(&request_); 
      request_stream << path << "\n" << file_size << "\n\n"; 
      std::cout << "Request size: " << request_.size() << std::endl; 
      tcp::resolver::query query(server_ip_or_host, port_string); 
      resolver_.async_resolve(query, boost::bind(&async_tcp_client::handle_resolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); 
     }; 
    private: 
     void handle_resolve(const boost::system::error_code & err, tcp::resolver::iterator endpoint_iterator) 
     { 
      if(!err) 
      { 
       tcp::endpoint endpoint = *endpoint_iterator; 
       socket_.async_connect(endpoint, boost::bind(&async_tcp_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); 
      } 
      else 
      { 
       std::cout << "Error: " << err.message() << '\n'; 
      } 
     }; 

     void handle_connect(const boost::system::error_code &err, tcp::resolver::iterator endpoint_iterator) 
     { 
      if(!err) 
      { 
       boost::asio::async_write(socket_, request_, boost::bind(&async_tcp_client::handle_write_file, this, boost::asio::placeholders::error)); 
      } 
      else if(endpoint_iterator != tcp::resolver::iterator()) 
      { 
       socket_.close(); 
       tcp::endpoint endpoint = *endpoint_iterator; 
       socket_.async_connect(endpoint, boost::bind(&async_tcp_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); 
      } 
      else 
      { 
       std::cout << "Error: " << err.message() << '\n'; 
      }; 
     } 

     void handle_write_file(const boost::system::error_code& err) 
     { 
      if(!err) 
      { 
       if(source_file.eof() == false) 
       { 
        source_file.read(buf.c_array(), (std::streamsize)buf.size()); 
        if(source_file.gcount()<= 0) 
        { 
         std::cout << "read file error" << std::endl; 
         return; 
        }; 
        std::cout << "Send " << source_file.gcount() << "bytes, total: " << source_file.tellg() << " bytes.\n"; 
        boost::asio::async_write(socket_, boost::asio::buffer(buf.c_array(), source_file.gcount()),boost::bind(&async_tcp_client::handle_write_file, this, boost::asio::placeholders::error)); 
        if(err) 
        { 
         std::cout << "Send error: " << err << std::endl; 
         return; 
        } 
       } 
       else 
        return; 
      } 
      else 
      { 
       std::cout << "Error: " << err.message() << "\n"; 
      } 
     }; 


     tcp::resolver resolver_; 
     tcp::socket socket_; 
     boost::array<char, 1024> buf; 
     boost::asio::streambuf request_; 
     std::ifstream source_file; 
    }; 

    class async_tcp_connection: public boost::enable_shared_from_this<async_tcp_connection> 
    { 
    public: 
     async_tcp_connection(boost::asio::io_service& io_service):socket_(io_service), file_size(0){} 
     void start() 
     { 
      if(debugmode) 
       debug_global << __FUNCTION__ << std::endl; 
      async_read_until(socket_, request_buf, "\n\n", boost::bind(&async_tcp_connection::handle_read_request, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
     } 
     boost::asio::ip::tcp::socket& socket(){return socket_;} 
    private: 
     boost::asio::streambuf request_buf; 
     size_t file_size; 
     std::ofstream output_file; 
     boost::asio::ip::tcp::socket socket_; 
     boost::array<char, 40960> buf; 
     void handle_read_request(const boost::system::error_code& err, std::size_t bytes_transferred) 
     { 
      if(err) 
      { 
       return handle_error(__FUNCTION__, err); 
      } 
      if(debugmode) 
       debug_global << __FUNCTION__ << "(" << bytes_transferred << ")" <<", in_avail = " << request_buf.in_avail() << ", size = " << request_buf.size() << ", max_size = " << request_buf.max_size() << ".\n"; 
      std::istream request_stream(&request_buf); 
      std::string file_path; 
      request_stream >> file_path; 
      request_stream >> file_size; 
      request_stream.read(buf.c_array(), 2); 
      if(debugmode) 
       debug_global << file_path << " size is " << file_size << ", tellg = " << request_stream.tellg() << std::endl; 
      size_t pos = file_path.find_last_of('\\'); 
      if(pos!= std::string::npos) 
       file_path = file_path.substr(pos+1); 
      output_file.open(file_path.c_str(), std::ios_base::binary); 
      if(!output_file) 
      { 
       if(debugmode) 
        debug_global << "Failed to open: " << file_path << std::endl; 
       return; 
      } 
      do{ 
       request_stream.read(buf.c_array(), (std::streamsize)buf.size()); 
       if(debugmode) 
        debug_global << __FUNCTION__ << " write " << request_stream.gcount() << " bytes.\n"; 
       output_file.write(buf.c_array(), request_stream.gcount()); 
      }while(request_stream.gcount() > 0); 
      async_read(socket_, boost::asio::buffer(buf.c_array(), buf.size()),boost::bind(&async_tcp_connection::handle_read_file_content, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
     } 

     void handle_read_file_content(const boost::system::error_code& err, std::size_t bytes_transferred) 
     { 
      if (bytes_transferred>0) 
      { 
       output_file.write(buf.c_array(), (std::streamsize)bytes_transferred); 
       if(debugmode) 
        debug_global << __FUNCTION__ << " recv " << output_file.tellp() << " bytes."<< std::endl; 
       if (output_file.tellp()>=(std::streamsize)file_size) 
       { 
        return; 
       } 
      } 
      if (err) 
      { 
       return handle_error(__FUNCTION__, err); 
      } 
      async_read(socket_, boost::asio::buffer(buf.c_array(), buf.size()), boost::bind(&async_tcp_connection::handle_read_file_content, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
     } 

     void handle_error(const std::string& function_name, const boost::system::error_code& err) 
     { 
      if(debugmode) 
       debug_global << __FUNCTION__ << " in " << function_name <<" due to " << err <<" " << err.message()<< std::endl; 
     } 
    }; 

    class async_tcp_server : private boost::noncopyable 
    { 
    public: 
     typedef boost::shared_ptr<async_tcp_connection> ptr_async_tcp_connection; 

     async_tcp_server(unsigned short port):acceptor_(io_service_, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), true) 
     { 
       ptr_async_tcp_connection new_connection_(new async_tcp_connection(io_service_)); 
       acceptor_.async_accept(new_connection_->socket(), boost::bind(&async_tcp_server::handle_accept, this,new_connection_, boost::asio::placeholders::error)); 
       io_service_.run(); 
     } 
     void handle_accept(ptr_async_tcp_connection current_connection, const boost::system::error_code& e) 
     { 
      if(debugmode) 
       debug_global << __FUNCTION__ << " " << e << ", " << e.message()<<std::endl; 
      if (!e) 
      { 
       current_connection->start(); 
       //ptr_async_tcp_connection new_connection_(new async_tcp_connection(io_service_)); 
       //acceptor_.async_accept(new_connection_->socket(), 
       // boost::bind(&async_tcp_server::handle_accept, this,new_connection_, 
       // boost::asio::placeholders::error)); 
      } 
     } 

     ~async_tcp_server() 
     { 
      io_service_.stop(); 
     } 
    private: 
     boost::asio::io_service io_service_; 
     boost::asio::ip::tcp::acceptor acceptor_; 
    }; 

如果我要發送的文件,我已經進入絕對路徑,如果我進入相對PA (例如, 「Image.jpg」),我收到錯誤信息「無法打開Image.jpg」。 全成調用函數後,我得到下面的輸出:

Adress is: <ip>:<port> and file is: <full file path> 
Request size: 91 
Send 1024 bytes, total: 1024 bytes 
Send 1024 bytes, total: 2048 bytes 
etc.. 
Send 1024 bytes, total: 20480 bytes 
Send 406 bytes, total: -1 bytes (Why?) 

在接收端,我沒有得到任何接收到的數據。爲什麼?我不明白爲什麼我的代碼不工作...
非常感謝!

+0

相對路徑是相對於當前的工作目錄......所以這是您的解決方案:在運行應用程序 – sehe

+0

@sehe當檢查工作目錄:據GetModuleFileName它是我當前的目錄,我把我的圖像 –

+1

[GetModuleFilename](http://msdn.microsoft.com/en-us/library/windows/desktop/ms683197(v = vs.85).aspx)得到你的_「包含指定模塊「_」的文件的完全限定路徑。 [當前工作目錄](http://bit.ly/1mP9DyD)是不同的東西。無論如何,看到我的答案。 – sehe

回答

4

UPDATE在我答案,我隨口說

我加了後綴.received到輸出文件名以防止覆蓋源。

我剛剛意識到這很可能是你的問題:

如果在同一臺機器上的接收器使用的代碼作爲發件人,您覆蓋源文件,而你仍然在發送... OOPS。


所以,我解決了代碼只是我可以運行它。

這裏的測試主要:

int main() 
{ 
    boost::thread_group g; 
    g.create_thread(rec_data); // get the receiver running 

    boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); 
    g.create_thread([] { send_data("test.cpp"); }); 

    g.join_all(); 
} 

我加了後綴.received到輸出文件名以防止覆蓋源。 運行此,它似乎很好地工作:

g++ -std=c++11 -Wall -pedantic -pthread test.cpp -lboost_system -lboost_thread 
./a.out 
md5sum test.cpp test.cpp.received 

我們得到的輸出

0dc16e7f0dc23cb9fce100d825852621 test.cpp.received 
0dc16e7f0dc23cb9fce100d825852621 test.cpp 

我也用一個PNG和一個93MB的可執行測試它。

全碼(也on Coliru, although Coliru doesn't allow network connections):

#include <boost/asio.hpp> 
#include <boost/array.hpp> 
#include <boost/bind.hpp> 
#include <boost/thread.hpp> 

#include <iostream> 
#include <fstream> 
#include <boost/enable_shared_from_this.hpp> 

using boost::asio::ip::tcp; 

static bool debugmode = true; 
static boost::mutex debug_mutex; 
static std::ostream debug_global(std::clog.rdbuf()); 

class async_tcp_client 
{ 
public: 
    async_tcp_client(boost::asio::io_service& io_service, const std::string& server, const std::string& path) 
     : resolver_(io_service), socket_(io_service) 
    { 
     size_t pos = server.find(':'); 
     if(pos==std::string::npos) 
     { 
      return; 
     } 
     std::string port_string = server.substr(pos+1); 
     std::string server_ip_or_host = server.substr(0,pos); 
     source_file.open(path, std::ios_base::binary|std::ios_base::ate); 
     if(!source_file) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << __LINE__ << "Failed to open " << path << std::endl; 
      return; 
     } 
     size_t file_size = source_file.tellg(); 
     source_file.seekg(0); 
     std::ostream request_stream(&request_); 
     request_stream << path << "\n" << file_size << "\n\n"; 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << "Request size: " << request_.size() << std::endl; 
     } 
     tcp::resolver::query query(server_ip_or_host, port_string); 
     resolver_.async_resolve(query, boost::bind(&async_tcp_client::handle_resolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); 
    }; 
private: 
    void handle_resolve(const boost::system::error_code & err, tcp::resolver::iterator endpoint_iterator) 
    { 
     if(!err) 
     { 
      tcp::endpoint endpoint = *endpoint_iterator; 
      socket_.async_connect(endpoint, boost::bind(&async_tcp_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); 
     } 
     else 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << "Error: " << err.message() << '\n'; 
     } 
    }; 

    void handle_connect(const boost::system::error_code &err, tcp::resolver::iterator endpoint_iterator) 
    { 
     if(!err) 
     { 
      boost::asio::async_write(socket_, request_, boost::bind(&async_tcp_client::handle_write_file, this, boost::asio::placeholders::error)); 
     } 
     else if(endpoint_iterator != tcp::resolver::iterator()) 
     { 
      socket_.close(); 
      tcp::endpoint endpoint = *endpoint_iterator; 
      socket_.async_connect(endpoint, boost::bind(&async_tcp_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); 
     } 
     else 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << "Error: " << err.message() << '\n'; 
     }; 
    } 

    void handle_write_file(const boost::system::error_code& err) 
    { 
     if(!err) 
     { 
      if(source_file) 
      //if(source_file.eof() == false) 
      { 
       source_file.read(buf.c_array(), (std::streamsize)buf.size()); 
       if(source_file.gcount()<= 0) 
       { 
        boost::mutex::scoped_lock lk(debug_mutex); 
        std::cout << "read file error" << std::endl; 
        return; 
       }; 
       { 
        boost::mutex::scoped_lock lk(debug_mutex); 
        std::cout << "Send " << source_file.gcount() << "bytes, total: " << source_file.tellg() << " bytes.\n"; 
       } 
       boost::asio::async_write(socket_, boost::asio::buffer(buf.c_array(), source_file.gcount()),boost::bind(&async_tcp_client::handle_write_file, this, boost::asio::placeholders::error)); 
      } 
      else 
      { 
       return; 
      } 
     } 
     else 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << "Error: " << err.message() << "\n"; 
     } 
    }; 


    tcp::resolver resolver_; 
    tcp::socket socket_; 
    boost::array<char, 1024> buf; 
    boost::asio::streambuf request_; 
    std::ifstream source_file; 
}; 

class async_tcp_connection: public boost::enable_shared_from_this<async_tcp_connection> 
{ 
public: 
    async_tcp_connection(boost::asio::io_service& io_service) 
     : socket_(io_service), file_size(0) 
    { 
    } 
    void start() 
    { 
     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << __FUNCTION__ << std::endl; 
     } 
     async_read_until(socket_, request_buf, "\n\n", boost::bind(&async_tcp_connection::handle_read_request, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 
    boost::asio::ip::tcp::socket& socket() 
    { 
     return socket_; 
    } 
private: 
    boost::asio::streambuf request_buf; 
    std::ofstream output_file; 
    boost::asio::ip::tcp::socket socket_; 
    size_t file_size; 
    boost::array<char, 40960> buf; 
    void handle_read_request(const boost::system::error_code& err, std::size_t bytes_transferred) 
    { 
     if(err) 
     { 
      return handle_error(__FUNCTION__, err); 
     } 
     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << __FUNCTION__ << "(" << bytes_transferred << ")" <<", in_avail = " << request_buf.in_avail() << ", size = " << request_buf.size() << ", max_size = " << request_buf.max_size() << ".\n"; 
     } 
     std::istream request_stream(&request_buf); 
     std::string file_path; 
     request_stream >> file_path; 
     request_stream >> file_size; 
     request_stream.read(buf.c_array(), 2); 
     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << file_path << " size is " << file_size << ", tellg = " << request_stream.tellg() << std::endl; 
     } 
     size_t pos = file_path.find_last_of('\\'); 
     if(pos!= std::string::npos) 
     { 
      file_path = file_path.substr(pos+1); 
     } 
     output_file.open(file_path + ".received", std::ios_base::binary); 
     if(!output_file) 
     { 
      if(debugmode) 
      { 
       boost::mutex::scoped_lock lk(debug_mutex); 
       debug_global << __LINE__ << "Failed to open: " << file_path << std::endl; 
      } 
      return; 
     } 
     do 
     { 
      request_stream.read(buf.c_array(), (std::streamsize)buf.size()); 
      if(debugmode) 
      { 
       boost::mutex::scoped_lock lk(debug_mutex); 
       debug_global << __FUNCTION__ << " write " << request_stream.gcount() << " bytes.\n"; 
      } 
      output_file.write(buf.c_array(), request_stream.gcount()); 
     } 
     while(request_stream.gcount() > 0); 
     async_read(socket_, boost::asio::buffer(buf.c_array(), buf.size()),boost::bind(&async_tcp_connection::handle_read_file_content, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_read_file_content(const boost::system::error_code& err, std::size_t bytes_transferred) 
    { 
     if (bytes_transferred>0) 
     { 
      output_file.write(buf.c_array(), (std::streamsize)bytes_transferred); 
      if(debugmode) 
      { 
       boost::mutex::scoped_lock lk(debug_mutex); 
       debug_global << __FUNCTION__ << " recv " << output_file.tellp() << " bytes."<< std::endl; 
      } 
      if (output_file.tellp()>=(std::streamsize)file_size) 
      { 
       return; 
      } 
     } 
     if (err) 
     { 
      return handle_error(__FUNCTION__, err); 
     } 
     async_read(socket_, boost::asio::buffer(buf.c_array(), buf.size()), boost::bind(&async_tcp_connection::handle_read_file_content, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_error(const std::string& function_name, const boost::system::error_code& err) 
    { 
     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << __FUNCTION__ << " in " << function_name <<" due to " << err <<" " << err.message()<< std::endl; 
     } 
    } 
}; 

class async_tcp_server : private boost::noncopyable 
{ 
public: 
    typedef boost::shared_ptr<async_tcp_connection> ptr_async_tcp_connection; 

    async_tcp_server(unsigned short port):acceptor_(io_service_, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), true) 
    { 
     ptr_async_tcp_connection new_connection_(new async_tcp_connection(io_service_)); 
     acceptor_.async_accept(new_connection_->socket(), boost::bind(&async_tcp_server::handle_accept, this,new_connection_, boost::asio::placeholders::error)); 
     io_service_.run(); 
    } 
    void handle_accept(ptr_async_tcp_connection current_connection, const boost::system::error_code& e) 
    { 
     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << __FUNCTION__ << " " << e << ", " << e.message()<<std::endl; 
     } 
     if (!e) 
     { 
      current_connection->start(); 
     } 
    } 

    ~async_tcp_server() 
    { 
     io_service_.stop(); 
    } 
private: 
    boost::asio::io_service io_service_; 
    boost::asio::ip::tcp::acceptor acceptor_; 
}; 

void send_data(std::string const& filename, std::string const& adr = "localhost:6767") 
{ 
    try 
    { 
     boost::asio::io_service io_service; 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << "Adress is: " << adr << " and file is: " << filename << '\n'; 
     } 

     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << adr << '\n'; 
     } 

     async_tcp_client client(io_service, adr, filename); 
     io_service.run(); 
    } 
    catch(std::exception const& e) 
    { 
     std::cerr << "Exception in " << __PRETTY_FUNCTION__ << ": " << e.what() << "\n"; 
    }; 
}; 

void rec_data(void) 
{ 
    try 
    { 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      std::cout << "Receiving data...\n"; 
     } 
     async_tcp_server recv_file_tcp_server(6767); 
     if(debugmode) 
     { 
      boost::mutex::scoped_lock lk(debug_mutex); 
      debug_global << "Received\n"; 
     } 
    } 
    catch(std::exception const& e) 
    { 
     std::cerr << "Exception in " << __PRETTY_FUNCTION__ << ": " << e.what() << "\n"; 
    }; 
}; 

int main() 
{ 
    boost::thread_group g; 
    g.create_thread(rec_data); // get the receiver running 

    boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); 
    g.create_thread([] { send_data("main.cpp"); }); 

    g.join_all(); 
} 
+2

我開始在遠程機器上接收器,因此不會覆蓋它(如我所想)。但我認爲我的主要問題是我通過PSExec遠程啓動接收器,認爲這個exe完全在遠程電腦上運行,這是錯誤的。當我在另一臺電腦上手動啓動exe時,一切正常...... –

+0

@arc_lupus很好,這使得它更有趣。我希望你沒有覆蓋任何重要的文件:) – sehe

+0

「重要文件」是什麼意思? –