MST

星途 面试题库

面试题:网络编程中Boost.Asio库的基本使用

请简述如何使用Boost.Asio库创建一个简单的TCP服务器,实现接受客户端连接并回显客户端发送的数据。请给出关键代码片段并解释其功能。
42.6万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试
  1. 引入必要的头文件
#include <iostream>
#include <boost/asio.hpp>

这部分代码引入了标准输入输出流头文件和Boost.Asio库的头文件,boost/asio.hpp包含了Asio库常用的功能。

  1. 定义处理客户端连接的类
class session : public std::enable_shared_from_this<session> {
public:
    session(boost::asio::io_context& io_context) : socket_(io_context) {}

    boost::asio::ip::tcp::socket& socket() {
        return socket_;
    }

    void start() {
        do_read();
    }

private:
    void do_read() {
        auto self(shared_from_this());
        boost::asio::async_read_until(socket_, buffer_, '\n',
            [this, self](boost::system::error_code ec, std::size_t length) {
                if (!ec) {
                    std::string data;
                    std::istream is(&buffer_);
                    std::getline(is, data);
                    std::cout << "Received: " << data << std::endl;
                    do_write(data);
                }
            });
    }

    void do_write(const std::string& data) {
        auto self(shared_from_this());
        boost::asio::async_write(socket_, boost::asio::buffer(data + "\n"),
            [this, self](boost::system::error_code ec, std::size_t /*length*/) {
                if (!ec) {
                    do_read();
                }
            });
    }

    boost::asio::ip::tcp::socket socket_;
    boost::asio::streambuf buffer_;
};
- `session`类继承自`std::enable_shared_from_this`,以便能够安全地使用`shared_from_this`来获取自身的`std::shared_ptr`。
- 构造函数接受一个`boost::asio::io_context&`,用于创建与客户端通信的`socket_`。
- `socket`函数返回与客户端连接的`socket`。
- `start`函数启动对客户端数据的读取。
- `do_read`函数使用`async_read_until`异步读取客户端数据,直到遇到换行符`'\n'`。读取成功后,将数据打印并调用`do_write`回显数据。
- `do_write`函数使用`async_write`异步将数据写回客户端,写完后再次调用`do_read`准备读取下一次数据。

3. 定义TCP服务器类

class server {
public:
    server(boost::asio::io_context& io_context, unsigned short port) : acceptor_(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), socket_(io_context) {
        do_accept();
    }

private:
    void do_accept() {
        acceptor_.async_accept(socket_,
            [this](boost::system::error_code ec) {
                if (!ec) {
                    std::make_shared<session>(std::move(socket_))->start();
                }
                do_accept();
            });
    }

    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::ip::tcp::socket socket_;
};
- `server`类的构造函数接受`boost::asio::io_context&`和端口号`port`,创建一个`acceptor_`来监听指定端口,并初始化一个`socket_`。
- `do_accept`函数使用`async_accept`异步接受客户端连接。接受成功后,创建一个`session`对象来处理该客户端连接,并启动`session`的读取操作。然后再次调用`do_accept`准备接受下一个客户端连接。

4. 主函数

int main() {
    try {
        boost::asio::io_context io_context;
        server s(io_context, 12345);

        std::vector<std::thread> threads;
        for (std::size_t i = 0; i < std::thread::hardware_concurrency(); ++i) {
            threads.emplace_back([&io_context]() { io_context.run(); });
        }

        for (auto& thread : threads) {
            thread.join();
        }
    } catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
    return 0;
}
- 在`main`函数中,创建一个`io_context`对象和一个`server`对象,监听端口`12345`。
- 创建多个线程来运行`io_context`,线程数量根据系统的CPU核心数确定,以充分利用多核资源。
- 最后等待所有线程执行完毕。如果捕获到异常,打印异常信息。