乐趣区

关于c++:BoostAsio使用协程进行网络编程

简介

本文基于 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 <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <string>
#include <asio.hpp>
#include <asio/ts/buffer.hpp>
#include <asio/ts/internet.hpp>

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<void> 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<void> handleConnection(tcp::socket&& socket)
    {std::vector<uint8_t> 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<std::mutex> 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<std::mutex> 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<uint8_t> 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<std::mutex> lock(coutLock);
        std::cerr << "Main Error:" << e.what() << '\n';}
}
New Connection From: 127.0.0.1:55647
hello, asio!
Read Error: End of file
退出移动版