Boost.Asio—使用协程进行网络编程

简介

本文基于 Boost.Asio 编写一个 TCP echo 程序. 且使用协程来处理异步逻辑.

Asio

下载:https://sourceforge.net/proje...

VS 中使用:项目 - 属性 - VC目录 - 包含目录,添加 YourPath\asio-1.18.2\include

官方文档:https://www.boost.org/doc/lib...

1. 头文件及全局变量

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using asio::ip::tcp;

static std::mutex coutLock;

// 简单起见,此处回显固定的消息
static std::string Message("hello, asio!");
static size_t MsgLength = Message.size();

2. TcpServer

// 异步
class TcpServer
{
public:
    TcpServer(asio::io_context& context, uint16_t port)
        : m_context(context),
          m_acceptor(context, tcp::endpoint(tcp::v4(), port))
    {
        waitForConnection();
    }

private:
    asio::awaitable waitForConnection()
    {
        while (true)
        {
            tcp::socket socket(m_context);
            co_await m_acceptor.async_accept(socket, asio::use_awaitable);

            coutLock.lock();
            std::cout << "New Connection From: " << socket.remote_endpoint() << '\n';
            coutLock.unlock();

            // 创建协程,处理新到的连接
            asio::co_spawn(socket.get_executor(), handleConnection(std::move(socket)), asio::detached);
        }
    }

    static asio::awaitable handleConnection(tcp::socket&& socket)
    {
        std::vector buffer(MsgLength);

        try
        {
            while (true)
            {
                std::size_t n = co_await asio::async_read(socket, asio::buffer(buffer), asio::use_awaitable);

                co_await asio::async_write(socket, asio::buffer(buffer, n), asio::use_awaitable);
            }
        }
        catch (const std::exception& e)
        {
            std::lock_guard lock(coutLock);
            std::cerr << "Handle Connection Error: " << e.what() << '\n';
        }
    }

private:
    asio::io_context& m_context;
    tcp::acceptor m_acceptor;
};

此时不用再传入回调函数,而是将回调函数替换为 asio::use_awaitable,然后再 co_await async_xxx(...); 即可.

3. TcpClient

// 同步
class TcpClient
{
public:
    TcpClient(asio::io_context& context)
        : m_context(context),
          m_socket(context),
          m_buffer(MsgLength)
    {}

    void connect(const std::string& host, const std::string& service)
    {
        try
        {
            tcp::resolver resolver(m_context);
            auto endpoints(resolver.resolve(host, service));
            asio::connect(m_socket, endpoints);
        }
        catch (const std::exception& e)
        {
            std::lock_guard lock(coutLock);
            std::cerr << "Connect Error: " << e.what() << '\n';
        }
    }

    void echo(const std::string& msg)
    {
        size_t length = asio::write(m_socket, asio::buffer(msg.c_str(), msg.size()));

        length = asio::read(m_socket, asio::buffer(m_buffer, length));

        coutLock.lock();
        for (std::size_t i = 0; i < length; i++)
        {
            std::cout << m_buffer[i];
        }
        std::cout << '\n';
        coutLock.unlock();

        m_socket.close();
    }

private:
    asio::io_context& m_context;
    tcp::socket m_socket;
    std::vector m_buffer;
};

4. 主程序

static void clientThread(asio::io_context& context)
{
    TcpClient client(context);

    client.connect("127.0.0.1", "6666");
    client.echo(Message);
}

int main()
{
    try
    {
        asio::io_context context;
        TcpServer server(context, 6666);

        std::thread t(clientThread, std::ref(context));
        t.detach();

        context.run();
    }
    catch (const std::exception& e)
    {
        std::lock_guard lock(coutLock);
        std::cerr << "Main Error: " << e.what() << '\n';
    }
}
New Connection From: 127.0.0.1:55647
hello, asio!
Read Error: End of file

你可能感兴趣的:(c++asio协程网络编程)