boost之asio

asio

asio是C++的准标准网络库,并且C++20标准库的网络部分将基于ASIO,需引入头文件#include <boost/asio.hpp>

ip地址

boost定义了表示ip地址的类型,支持ipv4和ipv6,提供ip::addressip::address_v4以及ip::address_v6三种类型。

  • 通过字符串构造ip地址:
#include <boost/asio.hpp>

namespace ba = boost::asio;
namespace bi = ba::ip;

int main(int argc, char* argv[])
{
    // 通过点分十进制转换为ipv4地址
    bi::address addrV4 = bi::make_address("127.0.0.1");
    assert(addrV4.is_v4());

    // 通过十六进制转换为ipv6地址
    bi::address addrV6 = bi::make_address("ABCD:EF01:2345:6789:ABCD:EF01:2345:6789");
    assert(addrV6.is_v6());

    // bi::address重载了流操作符,可以直接输出(所以也可以用boost::lexical_cast<string>(address))
    std::cout << addrV4 << std::endl;
    std::cout << addrV6 << std::endl;

    return 0;
}

ip地址+端口

对于tcp和udp两种协议,定义了对应的类型:ip::tcp::endpointip::udp::endpoint

  • 通过ip地址和端口号构造
int main(int argc, char* argv[])
{
    // 端口号直接传入就行,不用转换为网络序
    bi::tcp::endpoint ep(bi::make_address("127.0.0.1"), 1234);

    // endpoint也重载了流操作符
    std::cout << ep << std::endl;

    return 0;
}

域名解析

asio中提供ip::tcp::resolverip::udp::resolver实现域名解析,相当于unix网络编程中的getaddrinfo()接口封装:

  • 解析指定域名和端口对应的ip地址和端口信息:
int main(int argc, char* argv[])
{
    // 域名解析需要使用底层网络io
    ba::io_context io;
    bi::tcp::resolver resolver(io);

    // 对baidu域名进行解析
    auto endpoints = resolver.resolve("www.baidu.com", "https");
    for (auto& endpoint : endpoints) {
        std::cout << endpoint.endpoint() << std::endl;
    }

    return 0;
}

定时器

同步模式:

int main(int argc, char const *argv[])
{
    ba::io_context io;
    ba::steady_timer tm (io, ba::chrono::seconds(5));

    std::cout << "start timer" << std::endl;
    tm.wait();
    std::cout << "end wait" << std::endl;

    return 0;
}

异步模式:

int main(int argc, char const *argv[])
{
    ba::io_context io;
    ba::steady_timer tm (io, ba::chrono::seconds(5));

    tm.async_wait([] (boost::system::error_code ec) {
        std::cout << "time's up" << std::endl;
    });

    io.run();

    return 0;
}

周期定时器:

void heartbeat(std::shared_ptr<ba::steady_timer> tm, boost::system::error_code ec) {
    std::cout << "heart beat" << std::endl;
    tm->expires_after(ba::chrono::seconds(1));
    tm->async_wait([tm] (boost::system::error_code ec) {
        heartbeat(tm, ec);
    });
}

int main(int argc, char const *argv[])
{
    ba::io_context io;
    auto tm = std::make_shared<ba::steady_timer>(io, ba::chrono::seconds(1));

    tm->async_wait([tm] (boost::system::error_code ec) {
        heartbeat(tm, ec);
    });

    io.run();

    return 0;
}

buffer

asio使用的是proactor模式,也就是io操作不光是通知有了可读可写事件,并且会将可读写到调用者指定的buffer中,从调用者指定的buffer中取数据写入,所以asio提供了数据缓冲类型。
有两种buffer:mutable_bufferconst_buffer,buffer并不申请内存,它只是一个内存块的封装,本质上就一个void *data,size_t size的一个数据对,所以需要确保引用数据的生命周期。
buffer函数用于创建mutable_bufferconst_buffer对象,支持POD数组,PODarray,PODvectorstring类型:

#include <iostream>
#include <string>
#include <boost/asio.hpp>

namespace ba = boost::asio;

int main(int argc, char const *argv[])
{
    (void)argc;
    (void)argv;

    std::string str = "123";
    ba::mutable_buffer mbuf = ba::buffer(str);
    const std::string cstr = "123";
    ba::const_buffer cbuf = ba::buffer(cstr);

    std::cout << mbuf.size() << std::endl;
    std::cout << cbuf.size() << std::endl;

    return 0;
}

同步模式tcp客户端和服务端

以下是asio教程中关于daytime服务的tcp客户端和服务端代码:

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

namespace ba = boost::asio;
namespace bi = ba::ip;

int main(int argc, char const *argv[])
{
    (void)argc;
    (void)argv;

    ba::io_context io;
    bi::tcp::resolver resolver(io);
    auto endpoints = resolver.resolve("localhost", "daytime");
    bi::tcp::socket connSocket(io);
    ba::connect(connSocket, endpoints);

    std::array<char, 128> arr;
    while (true) {
        boost::system::error_code ec;
        size_t len = connSocket.read_some(ba::buffer(arr), ec);
        if (ba::error::eof == ec) {
            break;
        } else if (ec) {
            throw boost::system::system_error(ec);
        }
        std::cout.write(arr.data(), len);
    }

    return 0;
}
#include <iostream>
#include <string>
#include <array>
#include <ctime>
#include <boost/asio.hpp>

namespace ba = boost::asio;
namespace bi = ba::ip;

int main(int argc, char const *argv[])
{
    (void)argc;
    (void)argv;

    ba::io_context io;
    bi::tcp::acceptor acceptor(io, bi::tcp::endpoint(bi::tcp::v4(), 13));

    while (true) {
        bi::tcp::socket connSocket(io);
        acceptor.accept(connSocket);
        time_t now = time(0);
        std::string message = ctime(&now);
        ba::write(connSocket, ba::buffer(message));
    }

    return 0;
}
posted @ 2020-10-11 00:02  HachikoT  阅读(832)  评论(0编辑  收藏  举报