简介

本文基于 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:55647hello, asio!Read Error: End of file