独立ASIO异步未连接

时间:2016-08-18 10:52:42

标签: c++11 boost-asio

ASIO似乎是我项目中最好的异步跨平台网络库。但是,我无法让它实际连接。

首先,我没有使用Boost。我暂时在Windows上编译它,所以我不得不手动添加定义以告知ASIO我正在使用符合C ++ 11的编译器。

Source.cpp

#define TCPCLIENT_DEBUG
#include "TCPClient.hpp"
#include <iostream>

#define PORT "1234"
#define HOST "127.0.0.1"

int main() {
    DEBUG("Starting program...\n");
    namespace ip = asio::ip;

    asio::io_service io;
    ip::tcp::resolver::query query(HOST, PORT);
    ip::tcp::resolver resolver(io);
    decltype(resolver)::iterator ep_iter = resolver.resolve(query);

    TCPClient client(io, ep_iter);

    try {
        std::cin.get();
    }
    catch (const std::exception &e) { // mainly to catch Ctrl+C
        std::cout << e.what() << std::endl;
    }
    return 0;
}

TCPClient.hpp

#ifndef TCPCLIENT_HPP
#define TCPCLIENT_HPP

#include <functional>

#if defined(_DEBUG) || defined(TCPCLIENT_DEBUG)
#include <iostream>
#define DEBUG(dbg_msg) std::cerr << dbg_msg
#else
#define DEBUG(dbg_msg)
#endif

#define ASIO_STANDALONE
#define ASIO_HAS_CSTDINT
#define ASIO_HAS_STD_ARRAY
#define ASIO_HAS_STD_ADDRESSOF
#define ASIO_HAS_STD_SHARED_PTR
#define ASIO_HAS_STD_TYPE_TRAITS

#include <asio.hpp>
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 1024
#endif

class TCPClient {
public:
    TCPClient(asio::io_service& io, asio::ip::tcp::resolver::iterator endpoint_iter);
    void on_connect(const asio::error_code& err);

private:
    asio::io_service& m_io;                         // store the io service reference
    asio::ip::tcp::socket m_sock;                   // object's socket
    static const size_t bufSize{ BUFFER_SIZE };     // default buffer size
    char m_buffer[bufSize];                         // store the received data in a buffer
};

#endif//TCPCLIENT_HPP

TCPClient.cpp

#include "TCPClient.hpp"

TCPClient::TCPClient(asio::io_service& io, asio::ip::tcp::resolver::iterator endpoint_iter) : m_io{ io }, m_sock(io) {
    asio::ip::tcp::endpoint endpoint = *endpoint_iter;
    asio::error_code ec;

    m_sock.async_connect(
        endpoint,
        std::bind(
            &TCPClient::on_connect,
            this,
            std::placeholders::_1
        )
    );
}

void TCPClient::on_connect(const asio::error_code& err) {
    DEBUG("Connected successfully!\n");
}

在我看来on_connect从未被调用过。它只打印“正在启动程序......”。

使用netcat,我可以生成一个监听器,看到连接成功通过。

enter image description here

我的代码显然有什么问题?我现在只处理连接功能。

2 个答案:

答案 0 :(得分:2)

通过调用async_connect,您只注册一个异步操作。您应该在某处明确地调用io_service.run(), - 可能在main而不是std::cin.get(), - 以使您的异步操作真正执行并调用回调。

在幕后,asio使用epoll或类似的东西:它注册它感兴趣的事件(在你的情况下是套接字连接),然后等待事件发生。 io_service.run()正是等待的地方。

我建议你看一些boost :: asio asyncronous教程,比如this one

答案 1 :(得分:2)

处理程序仅在当前运行<item name="actionBarSize">@dimen/toolbar_height</item> 的线程中执行。由于永远不会运行io_service,因此永远不会执行连接处理程序。要解决此问题,请致电io_service::run()

运行io_service
io_service

Using a timer asynchronously Tutorial注意到运行TCPClient client(io, ep_iter); try { io.run(); } catch (const std::exception &e) { std::cout << e.what() << std::endl; }

的重要性
  

最后,我们必须在io_service对象上调用io_service::run()成员函数。

     

asio库提供了一种保证,即只能从当前调用io_service的线程调用回调处理程序。因此,除非调用io_service::run()函数,否则永远不会调用异步等待完成的回调。

     

io_service::run()功能也将继续运行,同时还有“工作”要做。在这个例子中,工作是定时器的异步等待,所以在定时器到期并且回调完成之前,调用不会返回。

     

重要的是要记住在致电io_service::run()之前给io_service做一些工作。例如,如果我们忽略了对io_service::run()的上述调用,则deadline_timer::async_wait()将无法完成任何工作,因此io_service将立即返回。