ACE小技巧:在ACE_Acceptor框架中,自定义服务处理器的创建

本文介绍如何在ACE_Acceptor框架中自定义服务处理器的创建过程。通过重写make_svc_handler()函数,可以实现如从预分配池获取处理器对象、传递额外信息等功能。

ACE小技巧:在ACE_Acceptor框架中,自定义服务处理器的创建

Stone Jiang

ACE_Acceptor框架使对新连接的侦听变得容易,也使创建和激活新连接的ACE_Svc_Handler的派生类变得容易。之前我们已经了解了ACE_Svc_Handle::open()挂勾函数和服务处理器初始化时它所扮演的角色。本文我们回退几步,来了解服务处理器是如何实例化的以及我们如何自定义它的行为。

再看看ACE_Acceptor类,它是一个模板类,第一个模板参数ACE_Accetpor是代表与服务建立连接的处理器。当新的连接建立时,ACE_Acceptor调用make_svc_handler()挂勾函数来实际创建的新建服务处理器对象。ACE_Acceptor::make_svc_handler()的实现如下:

template <class SVC_HANDLE,ACE_PEER_ACCEPTOR_1>
int
ACE_Acceptor
<SVC_HANDLE, ACE_PEER_ACCEPTOR_2>::make_svc_handler(SVC_HANDLE*& sh)
{
  ACE_TRACE (
"ACE_Acceptor<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::make_svc_handler");  if (sh == 0)
    ACE_NEW_RETURN (sh,
                    SVC_HANDLER,
                    
-1);  // Set the reactor of the newly created <SVC_HANDLER> to the same
  
// reactor that this <ACE_Acceptor> is using.
  sh->reactor (this->reactor ());
  
return 0;

}

 

默认的实现包括了两步基本操作:
1.  获得一个新的SVC_HANLDER对象, 这里是使用的new运算符分配的。
2.  设置新的服务处理器的reactor指针为ACE_Accetpor使用的reactor的。

然而,如果应用程序需要通过其它方式获得SVC_HANDLER对象,而不是通过默认的构造函数那种动态分配,这又该怎么办呢?举例来说,我们可能需要:
 . 从一个预分配的池中获得SVC_HANDLER对象;
 . 为新创建的SVC_HANDLER传入一些额外的信息
 . 使用单体的SVC_HANDLER

上面这些情形,我们都可以自定义make_svc_handler()挂勾函数来实现必要的行为。例如,假定我们新的处理器需要拥有一个处理所有对所有接收到的消息进行集中处理的中心处理器。这个中心处理器我们用类Processor表示。我们需要每个服务处理器都拥有一个指向中心处理器的指针,而不是使Processor成为一个全局访问的指针(使用全局变量的种种弊端本文不作详述)。我们的解决办法是: 从ACE_Accetor派生一个新类,这个新类拥有Processor的指针作成员,并且,在创建新和服务处理器(Service)的时候,把这个 Processor的指针作参数传进去。

新的acceptor类可以这样定义:

class My_Acceptor : public ACE_Acceptor<Service, ACE_SOCK_ACCEPTOR>
{
public:
  My_Acceptor (Processor 
*processor) : processor_ (processor) { };
  
  
int make_svc_handler (Service *&sh)
    
{
      
if (sh == 0)
        ACE_NEW_RETURN (sh,
                        Service (
this->processor_),
                        
-1);      // Set the reactor of the newly created <SVC_HANDLER> to the same
      
//  reactor that this <ACE_Acceptor> is using.
      sh->reactor (this->reactor ());
      
return 0;
    }


private:
  Processor 
*processor_;
}

 

就这样,现在,当My_Acceptor接受新连接的时候,make_svc_handler()挂勾函数分配一个新的处理器(Service),并把Processor*作为参数传进去。需要注意的事,尽管这里使用

的是这一个构造函数Service(Processor*)。我们仍需求为Service类定义默认的构造函数,以满足模板类ACE_Acceptor的需要。

 

<think>我们有两个问题需要解答: 1. 是否存在 `std::unique_ptr<tcp::async_accept> acceptor_{ nullptr };` 这样的用法? 2. 解释 `std::unique_ptr<tcp::acceptor> acceptor_{ nullptr };` 首先,我们需要明确的是:`tcp::acceptor` 是一个类型(在Boost.Asio中通常是`boost::asio::ip::tcp::acceptor`),而`async_accept`是一个成员函数,不是一个类型。 因此,我们只能有指向`tcp::acceptor`的指针,而不能有指向`tcp::async_accept`的指针,因为后者不是一个类型。 下面详细解释: ### 1. `std::unique_ptr<tcp::acceptor> acceptor_{ nullptr };` - 这是一个智能指针,用于管理一个`tcp::acceptor`对象。 - 使用`std::unique_ptr`可以自动管理`acceptor`的生命周期,避免内存泄漏。 - 初始化为`nullptr`表示当前不拥有任何对象。 ### 2. 关于`std::unique_ptr<tcp::async_accept> acceptor_{ nullptr };` - 这是不合法的,因为`tcp::async_accept`不是一个类型,而是一个成员函数。 - `async_accept`函数用于异步接受一个连接,它属于`tcp::acceptor`类。 ### 正确使用示例: ```cpp #include <boost/asio.hpp> #include <memory> using boost::asio::ip::tcp; class Server { public: Server(boost::asio::io_context& io_context, short port) : acceptor_(std::make_unique<tcp::acceptor>(io_context, tcp::endpoint(tcp::v4(), port))) { // 初始化acceptor后,可以开始监听和接受连接 } // 异步接受连接 void do_accept() { // 需要创建一个新的socket(通常由连接使用) auto socket = std::make_shared<tcp::socket>(acceptor_->get_executor()); acceptor_->async_accept(*socket, [this, socket](const boost::system::error_code& ec) { if (!ec) { // 处理新连接,例如创建一个会话并启动 } // 继续接受下一个连接 do_accept(); }); } private: std::unique_ptr<tcp::acceptor> acceptor_; }; ``` ### 为什么使用`std::unique_ptr`管理`acceptor`? - **资源管理**:确保在对象销毁时(例如服务器关闭时)`acceptor`被正确关闭和销毁。 - **延迟初始化**:有时我们可能需要在运行时根据条件创建`acceptor`,使用智能指针可以方便地管理动态创建的对象。 - **所有权明确**:`unique_ptr`明确表示该对象是独占所有权的,不能被复制,只能移动。 ### 常见错误: - 试图创建指向成员函数的指针:`tcp::async_accept`是一个函数,不能作为模板参数传递给`std::unique_ptr`。 - 使用`std::unique_ptr`时未正确初始化:在构造`acceptor`之前就使用了它(例如调用`listen`或`async_accept`)。 ### 总结: - 只能使用`std::unique_ptr`来管理类型(如`tcp::acceptor`),不能用来管理函数(如`async_accept`)。 - 使用智能指针管理资源是C++现代编程的最佳实践之一。 --- §§相关问题§§: 1. 在Boost.Asio中,`tcp::acceptor`的主要作用是什么? 2. 使用`std::unique_ptr`管理Boost.Asio对象有什么好处? 3. 如何正确地在类中使用`std::unique_ptr`来管理一个`tcp::socket`? 4. 在异步操作中,如何确保`tcp::acceptor`在服务器关闭时被安全销毁?</think>### 问题分析 `std::unique_ptr<tcp::acceptor>` 是合法且常用的模式,而 `std::unique_ptr<tcp::async_accept>` 是**无效的语法**。原因如下: --- ### 1. `std::unique_ptr<tcp::acceptor> acceptor_{ nullptr };` **含义**: - `tcp::acceptor` 是 Boost.Asio 中的**类型**(表示 TCP 监听套接字) - 使用 `std::unique_ptr` 管理该对象的生命周期 - `nullptr` 初始化表示当前未分配实际对象 **典型用法**: ```cpp #include <boost/asio.hpp> #include <memory> using boost::asio::ip::tcp; class Server { public: Server(boost::asio::io_context& io_context) : io_context_(io_context), acceptor_(std::make_unique<tcp::acceptor>( io_context_, tcp::endpoint(tcp::v4(), 8080) // 监听8080端口 )) { acceptor_->listen(); // 开始监听 } private: boost::asio::io_context& io_context_; std::unique_ptr<tcp::acceptor> acceptor_; // 正确:管理acceptor对象 }; ``` --- ### 2. `std::unique_ptr<tcp::async_accept>` 为何无效? **根本原因**: - `tcp::async_accept` 是**成员函数**,不是类型 - `std::unique_ptr` 的模板参数必须是**对象类型**,不能是函数 **正确认知**: - `async_accept` 是 `tcp::acceptor` 类的成员函数: ```cpp class tcp::acceptor { public: template <typename AcceptHandler> void async_accept(AcceptHandler handler); // 成员函数 }; ``` --- ### 异步接受连接的正确方式 若需异步操作,应在 `tcp::acceptor` 上调用 `async_accept`: ```cpp class Server { public: void start_accept() { auto new_socket = std::make_shared<tcp::socket>(io_context_); acceptor_->async_accept( *new_socket, [this, new_socket](boost::system::error_code ec) { if (!ec) handle_connection(new_socket); start_accept(); // 继续接受新连接 } ); } private: void handle_connection(std::shared_ptr<tcp::socket> socket) { // 处理连接... } }; ``` --- ### 关键区别总结 | 代码片段 | 有效性 | 说明 | |-----------------------------------|--------|-------------------------------| | `std::unique_ptr<tcp::acceptor>` | 有效 ✅ | 管理监听套接字对象 | | `std::unique_ptr<tcp::async_accept>` | 无效 ❌ | `async_accept` 是函数而非类型 | --- ### 为什么使用 `std::unique_ptr` 管理 Acceptor? 1. **资源安全**:自动释放底层套接字资源 2. **所有权明确**:独占式管理避免拷贝问题 3. **延迟初始化**:可在运行时动态创建对象 4. **异常安全**:构造函数失败时自动清理 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值