简介
本文基于 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