2016-08-20 1 views
-1

クライアントコードからサーバーに非同期メッセージを書き込もうとしました。ただし、サーバーは0バイトを受け取ります。Boost :: Asio Serverは、書き込みハンドルが終了した後でも、クライアントから空のメッセージを読み込みます。

Cliente出力: あなたは、あなたがサーバーから次のメッセージ受信 接続されている: サーバーがオンラインである:...

サーバーの出力を送信する 土8月20日午後5時42分01秒2016 を! 127.0.0.1:51973接続済み! クライアントはメッセージを受信しました。

サーバーのソース:

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

std::string make_daytime_string() 
{ 
    using namespace std; // For time_t, time and ctime; 
    time_t now = time(0); 
    return ctime(&now); 
} 


class tcp_connection: public boost::enable_shared_from_this<tcp_connection> 
{ 
public: 
    typedef boost::shared_ptr<tcp_connection> pointer; 

    static pointer create(boost::asio::io_service& io_service) 
    { 
     return pointer(new tcp_connection(io_service)); 
    } 

    tcp::socket& socket() 
    { 
     return socket_; 
    } 

    // Call boost::asio::async_write() to serve the data to the client. 
    // We are using boost::asio::async_write(), 
    // rather than ip::tcp::socket::async_write_some(), 
    // to ensure that the entire block of data is sent. 

    void start() 
    { 
     // The data to be sent is stored in the class member m_message 
     // as we need to keep the data valid 
     // until the asynchronous operation is complete. 

     m_message = make_daytime_string(); 

     // When initiating the asynchronous operation, 
     // and if using boost::bind(), 
     // we must specify only the arguments 
     // that match the handler's parameter list. 
     // In this code, both of the argument placeholders 
     // (boost::asio::placeholders::error 
     // and boost::asio::placeholders::bytes_transferred) 
     // could potentially have been removed, 
     // since they are not being used in handle_write(). 

     std::cout << socket_.remote_endpoint().address().to_string() << ":" << socket_.remote_endpoint().port() << " connected!" << std::endl; 

     boost::asio::async_write(socket_, boost::asio::buffer(m_message), 
           boost::bind(&tcp_connection::handle_write, shared_from_this())); 

     boost::asio::async_read(socket_, boost::asio::buffer(_buffer), boost::bind(&tcp_connection::handle_receive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 


private: 
    tcp_connection(boost::asio::io_service& io_service) 
    : socket_(io_service) 
    { 
    } 
    // handle_write() is responsible for any further actions 
    // for this client connection. 

    void handle_write() // call back.. when it finishes sending, we come here 
    { 
     std::cout << "Client has received the messaged. " << std::endl; 
    } 

    void handle_receive(const boost::system::error_code& ErrorCode, std::size_t bytes_transferred) 
    { 
     std::cout << "You received the following message from the server:" << std::endl; 
     std::cout.write(_buffer.data(), bytes_transferred); 

    } 

    tcp::socket socket_; 
    std::string m_message; 
    boost::array<char, 126> _buffer; 
}; 

class tcp_server 
{ 
public: 
    tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 7171)) 
    { 
     // start_accept() creates a socket and 
     // initiates an asynchronous accept operation 
     // to wait for a new connection. 
     start_accept(); 
    } 

private: 
    void start_accept() 
    { 
     // creates a socket 
     tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); 

     // initiates an asynchronous accept operation 
     // to wait for a new connection. 
     acceptor_.async_accept(new_connection->socket(), 
           boost::bind(&tcp_server::handle_accept, this, new_connection, 
              boost::asio::placeholders::error)); 
    } 

    // handle_accept() is called when the asynchronous accept operation 
    // initiated by start_accept() finishes. It services the client request 
    void handle_accept(tcp_connection::pointer new_connection, 
         const boost::system::error_code& error) 
    { 
     if (!error) 
     { 
      new_connection->start(); 
     } 

     // Call start_accept() to initiate the next accept operation. 
     start_accept(); 
    } 

    tcp::acceptor acceptor_; 
}; 

int main() 
{ 
    std::cout << "Server is online!" << std::endl; 
    try 
    { 
     boost::asio::io_service io_service; 

     tcp_server server(io_service); 

     io_service.run(); 

    } 
    catch (std::exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
    } 

    return 0; 
} 

クライアントソース:

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

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

std::string make_daytime_string() 
{ 
    using namespace std; // For time_t, time and ctime; 
    time_t now = time(0); 
    return ctime(&now); 
} 

class Connection 
{ 
public: 
    Connection(boost::asio::io_service& io) : _socket(io){} 

    void connect(tcp::resolver::iterator& point) 
    { 
     boost::asio::async_connect(_socket, point, boost::bind(&Connection::onConnected, this, boost::asio::placeholders::error)); 
    } 

    void onConnected(const boost::system::error_code& ErrorCode) 
    { 
     std::cout << "You are connected" << std::endl; 

     // receive first message on onReceive 
     boost::asio::async_read(_socket, boost::asio::buffer(_buffer), boost::bind(&Connection::onReceive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 

    void onSend(const boost::system::error_code& ErrorCode, std::size_t bytes_transferred) 
    { 
     std::cout << "Sending..." << std::endl; 
    } 

    void onReceive(const boost::system::error_code& ErrorCode, std::size_t bytes_transferred) 
    { 
     std::cout << "You received the following message from the server:" << std::endl; 
     std::cout.write(_buffer.data(), bytes_transferred); 

     // send first message on onSend 
     m_message = make_daytime_string(); 
     boost::asio::async_write(_socket, boost::asio::buffer(m_message), boost::bind(&Connection::onSend, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 

    tcp::socket& getSocket() 
    { 
     return _socket; 
    } 
private: 
    tcp::socket _socket; 
    boost::array<char, 126> _buffer; 
    std::string m_message; 
}; 

int main() 
{ 
    try 
    { 
     boost::asio::io_service io_service; 

     tcp::resolver resolver(io_service); 

     tcp::resolver::query query("127.0.0.1", "7171"); 

     tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); 

     Connection conn(io_service); 
     conn.connect(endpoint_iterator); 

     io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
    } 

    return 0; 
} 

@edit:

新しいクライアントコード:

class Connection : public boost::enable_shared_from_this<Connection> 
{ 
public: 
    typedef boost::shared_ptr<Connection> pointer; 

    static pointer create(boost::asio::io_service& io_service) 
    { 
     return pointer(new Connection(io_service)); 
    } 


    tcp::socket& socket() 
    { 
     return _socket; 
    } 

    void connect(tcp::resolver::iterator& point) 
    { 
     boost::asio::async_connect(_socket, point, boost::bind(&Connection::connect_handler, this, boost::asio::placeholders::error)); 
    } 

    void connect_handler(const boost::system::error_code& error) 
    { 
     if(error) 
     { 
      std::cout << "Error on connect_handler: " << error.message() << std::endl; 
      return; 
     } 

     std::cout << "You are connected to the server." << std::endl; 
     start(); 

    } 

    void start() 
    { 
     start_write(); 
     start_read(); 
    } 

private: 
    // private ctor 
    Connection(boost::asio::io_service& io) : _socket(io){} 

    void start_write() 
    { 
     _daymessage = make_daytime_string(); 

     boost::asio::async_write(_socket, boost::asio::buffer(_daymessage), 
           boost::bind(&Connection::handle_write, shared_from_this(), 
              boost::asio::placeholders::error, 
              boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_write(const boost::system::error_code& error, 
         size_t bytes) 
    { 
     if(error) 
     { 
      std::cout << "Error on handle write: " << error.message() << std::endl; 
      return; 
     } 

     std::cout << "Message has been sent!" << std::endl; 
     start_write(); 
    } 

    void start_read() 
    { 
     // Start an asynchronous operation to read a newline-delimited message. 
     boost::asio::async_read_until(_socket, _buffer, '\n', 
             boost::bind(&Connection::handle_read, shared_from_this(), 
                boost::asio::placeholders::error, 
                boost::asio::placeholders::bytes_transferred)); 
    } 

    void handle_read(const boost::system::error_code& error, size_t bytes) 
    { 
     if(error) 
     { 
      std::cout << "Error on handle read: " << error.message() << std::endl; 
      return; 
     } 

     // Extract the newline-delimited message from the buffer. 
     std::string line; 
     std::istream is(&_buffer); 
     std::getline(is, line); 

     if (!line.empty()) 
     { 
      std::cout << "Received: " << line << "\n"; 
     } 

     start_read(); 
    } 

    tcp::socket _socket; 
    std::string _daymessage; 
    boost::asio::streambuf _buffer; 
}; 

int main() 
{ 
    std::cout << "Client is running!" << std::endl; 

    try 
    { 
     boost::asio::io_service io_service; 

     tcp::resolver resolver(io_service); 

     tcp::resolver::query query("127.0.0.1", "7171"); 

     tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); 

     auto connection = Connection::create(io_service); 

     connection->connect(endpoint_iterator); 

     io_service.run(); 
    } 
    catch (std::exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
    } 

    return 0; 
} 
あなたは、サーバーから次のようなメッセージを受け取りました

obs:パブリックctorを使用してmake_sharedでインスタンス化するときに、「tr1 :: bad_weak_ptr」を取得しました。プライベートctorと静的メンバーfuncは正常に動作しました。

+0

。 –

+0

私は何を求めているのか分かりませんでした。今、私は質問とトピックをリファクタリングしました。あなたが望むなら、新しい編集を見てください。 –

+0

これは本当です、大丈夫です。 –

答えて

0

あなたが提供したコードを使用して多くの問題があります。

  • をサーバー接続クラスでは、あなたの代わりにshared_from_thisを使用しての生のthisポインタ を使用しています。これにより、リソースが スコープから外れているため、 の操作がcancelledになっていました。
  • コードでは、サイズが126のバッファーを使用してasync_readを使用しています。 多くのバイトが少なくとも受け取られるまで、操作は完了しないと思います。代わりにasync_read_untilを使用してください。プロトコルや定義済みのバイトシーケンスがないため、コード「 」をデリミタとして「\ n」を送信するように変更しました。
  • 受信したエラーコードを無視しないでください。

修正サーバコード:

class tcp_connection: public boost::enable_shared_from_this<tcp_connection> 
{ 
public: 
    typedef boost::shared_ptr<tcp_connection> pointer; 

    static pointer create(boost::asio::io_service& io_service) 
    { 
     return pointer(new tcp_connection(io_service)); 
    } 

    tcp::socket& socket() 
    { 
     return socket_; 
    } 

    // Call boost::asio::async_write() to serve the data to the client. 
    // We are using boost::asio::async_write(), 
    // rather than ip::tcp::socket::async_write_some(), 
    // to ensure that the entire block of data is sent. 

    void start() 
    { 
     // The data to be sent is stored in the class member m_message 
     // as we need to keep the data valid 
     // until the asynchronous operation is complete. 

     m_message = make_daytime_string(); 

     // When initiating the asynchronous operation, 
     // and if using boost::bind(), 
     // we must specify only the arguments 
     // that match the handler's parameter list. 
     // In this code, both of the argument placeholders 
     // (boost::asio::placeholders::error 
     // and boost::asio::placeholders::bytes_transferred) 
     // could potentially have been removed, 
     // since they are not being used in handle_write(). 

     std::cout << socket_.remote_endpoint().address().to_string() << ":" << socket_.remote_endpoint().port() << " connected!" << std::endl; 

     boost::asio::async_write(socket_, boost::asio::buffer(m_message), 
           boost::bind(&tcp_connection::handle_write, shared_from_this())); 
     boost::asio::async_read_until(socket_, 
      _buffer, 
      '\n', 
      boost::bind(&tcp_connection::handle_receive, 
       shared_from_this(), 
       boost::asio::placeholders::error)); 
    } 


private: 
    tcp_connection(boost::asio::io_service& io_service) 
    : socket_(io_service) 
    { 
    } 
    // handle_write() is responsible for any further actions 
    // for this client connection. 

    void handle_write() // call back.. when it finishes sending, we come here 
    { 
     std::cout << "Client has received the messaged. " << std::endl; 
    } 

    void handle_receive(const boost::system::error_code& ErrorCode) 
    { 
     std::cout << "You received the following message from the server: "<< std::endl; 
     if (ErrorCode) { 
      std::cout << "Error occured: " << ErrorCode.message() << std::endl; 
      return; 
     } 
     std::string line; 
     std::istream is(&_buffer); 
     std::getline(is, line); 
     std::cout << line << std::endl; 

    } 

    tcp::socket socket_; 
    std::string m_message; 
    boost::asio::streambuf _buffer; 
}; 

修正クライアントコード:あなたの問題のソースコードの上に置く

class Connection: public boost::enable_shared_from_this<Connection> 
{ 
public: 
    Connection(boost::asio::io_service& io) : _socket(io){} 

    void connect(tcp::resolver::iterator& point) 
    { 
     boost::asio::async_connect(_socket, point, boost::bind(&Connection::onConnected, this, boost::asio::placeholders::error)); 
    } 

    void onConnected(const boost::system::error_code& ErrorCode) 
    { 
     std::cout << "You are connected" << std::endl; 

     // receive first message on onReceive 
     boost::asio::async_read_until(_socket, 
      _buffer, 
      '\n', 
      boost::bind(&Connection::onReceive, 
       this, boost::asio::placeholders::error)); 
    } 

    void onSend(const boost::system::error_code& ErrorCode, std::size_t bytes_transferred) 
    { 
     std::cout << "Sending..." << std::endl; 
    } 

    void onReceive(const boost::system::error_code& ErrorCode) 
    { 
     std::cout << "You received the following message from the server:" << std::endl; 
     //std::cout.write(_buffer.data(), bytes_transferred); 

     // send first message on onSend 
     m_message = make_daytime_string() + '\n'; 
     std::cout << "Sending " << m_message << std::endl; 
     boost::asio::async_write(_socket, boost::asio::buffer(m_message), boost::bind(&Connection::onSend, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
    } 

    tcp::socket& getSocket() 
    { 
     return _socket; 
    } 
private: 
    tcp::socket _socket; 
    boost::asio::streambuf _buffer; 
    std::string m_message; 
}; 
+0

まずはあなたの返事に感謝します。 これはかなりうまくいった。しかし、私はコンストラクタをpublicにしておき、make_sharedでクラスをインスタンス化し、すべてのハンドラにshared_from_this()を渡そうとしました。それはうまく動かず、私は "tr1:bad_weak_ptr"を受け取りました。だから私がやったことは、私はプライベートctorを宣言し、静的関数を使ってクラスをインスタンス化し、サーバ上と同じようにそのオブジェクトの共有ポインタを返します。そして今、私はオブジェクトに関連するメインのshared_ptrを持っています。それは働いている。あなたはそれが良いと思いますか、またはリファクタリングが良いかもしれませんか?そしてなぜtr1:悪いですか? –

+0

メイントピックに新しいコードが投稿されましたので、 –

+0

@BrunoMiguel私はあなたの 'connect'メソッドに' shared_from_this'ではなく 'this'ポインタを使用しています。なぜあなたが 'bad_weak_ptr'を打っていたのか分かりませんが、あなたが提案したことは私にはうまく見えます。私が見る唯一の論理的な問題は、クライアントが複数の 'start_write'リクエストを発行していますが、(あなたが投稿した元のコードごとに)サーバーが一度だけそれを読み込むということです。 – Arunmu

関連する問題