在关闭应用程序之前,不会调用handle_write

时间:2013-12-27 04:57:05

标签: visual-c++ boost-asio

我正在使用Boost-asio在Windows环境中的Java和C ++应用程序之间进行IPC。我现在正在C ++方面进行一些简单的测试,现在将数据写入“localhost”服务器中的端口100。这是我的代码:

int _tmain(int argc, _TCHAR* argv[])
{
    boost::asio::io_service ioService;

    TCPClient client(ioService, "localhost", "100");
    ioService.run();

    client.Write("Heloo!!!");
    getchar();
}

TCPClient课程:

#include <iostream>
#include <stdio.h>
#include <ostream>

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

using namespace std;
using boost::asio::ip::tcp;

class TCPClient {
public:
    // Constructor
    TCPClient::TCPClient(boost::asio::io_service& IO_Service, const std::string& server, const std::string& port)
        : resolver_(IO_Service), socket_(IO_Service){
        connected = false;

        // Query donde defino nombre del servidor y puerto
        tcp::resolver::query query(server, port);

        resolver_.async_resolve(query,
            boost::bind(&TCPClient::handle_resolve, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::iterator));
    }

private:
    tcp::resolver   resolver_;
    tcp::socket     socket_;
    bool connected;

public:
    void Write(const std::string& data){
        size_t s = 8;

        boost::asio::async_write(   socket_,
                                    boost::asio::buffer(data, s),
                                    boost::bind(&TCPClient::handle_write,
                                    this, boost::asio::placeholders::error,
                                    boost::asio::placeholders::bytes_transferred)
                                );
        std::cout << "async_write executed" << std::endl;
    }

private:
    // Resolucion de la direccion del servidor
    void handle_resolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator){
        if (!err){
            // Intentamos conectarnos al primer endpoint en la lista
            tcp::endpoint endpoint = *endpoint_iterator;
            socket_.async_connect(  endpoint,
                                    boost::bind(&TCPClient::handle_connect, this,
                                    boost::asio::placeholders::error, ++endpoint_iterator));
        }
        else{
            std::cout << "Error: " << err.message() << std::endl;
        }
    }

    // Conexion al servidor
    void handle_connect(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator){
        if (!err){
            connected = true;
            std::cout << "Connected" << std::endl;
        }
        else if (endpoint_iterator != tcp::resolver::iterator()){
            // Conexion fallida, intentemos con el siguiente endpoint
            socket_.close();
            tcp::endpoint endpoint = *endpoint_iterator;

            socket_.async_connect(  endpoint,
                                    boost::bind(&TCPClient::handle_connect, this,
                                    boost::asio::placeholders::error, ++endpoint_iterator));
        }
        else{
            std::cout << "Error: " << err.message() << std::endl;
        }
    }

    void handle_write(const boost::system::error_code& error, std::size_t bytes_transferred){
        if (!error){
            std::cout << "Handle_write() sent bytes" << bytes_transferred << std::endl;
        }
        else {
            std::cout << "Handle_write() error:" << error << std::endl;
        }
    }


};

所以我在Windows机器上使用端口侦听器,并成功设法连接到端口100:

enter image description here

但我没有收到数据Helloo!!,因为您可以看到handle_connect()未被调用。但是,当我关闭C ++应用程序时,数据被发送:

enter image description here

我错过了什么?我读了很多例子,我对这个库感到很困惑。


修改

好的,这是我的新主要代码:

int _tmain(int argc, _TCHAR* argv[])
{
    boost::asio::io_service ioService;

    TCPClient client(ioService, "localhost", "4000");
    ioService.run();

    client.Write("Heloo!!!");
    ioService.reset();
    ioService.run();
    getchar();
}

我重新启动服务以便发送数据,现在我看到handle_write正在调用,但在关闭应用程序之前我仍然无法看到传入的数据:

enter image description here

1 个答案:

答案 0 :(得分:0)

简而言之,当io_service::run()返回时,io_service已失去工作。即使TCPClient::write()io_service添加了更多工作,但io_service的事件循环也不会再次被提供服务,从而导致永远不会调用TCPClient::handle_write()。考虑一下:

  • 重置io_service,以便通过io_service::reset()再次run(),然后调用io_service::run()
  • 通过保证每个处理程序为io_service添加额外的工作或构建io_service::work对象,重构程序以使io_service永远不会失效。

要更深入地了解io_service::run(),请考虑阅读this回答。

此外,程序调用未定义的行为,因为它无法满足boost::asio::async_write()buffers参数的生命周期要求:

  

[...]调用者保留了底层内存块的所有权,这必须保证它们在调用处理程序之前保持有效。

调用client.write("Heloo!!!")时,会构造一个临时std::string并传递给TCPClient::write()。然后将临时string用作buffers的{​​{1}}参数。由于async_write()不保证在调用TCPClient::write()完成处理程序之前它不会返回,因此临时的生命周期违反了async_write()的要求,导致未定义的行为。