如何使用RAII建模套接字

时间:2012-04-26 19:27:56

标签: c++ sockets raii

我是C ++的新手(来自C)。我从概念上理解RAII应该如何工作,但我无法在其中安装一个简单的套接字连接处理程序。

当前代码:

void accept_ev(event_handler::token &t, int listenfd)
{
    int newfd = accept(listenfd, NULL, NULL);

    if (newfd < 0)
        throw api_server_accept_failed(*this, errno);

    connections.insert(api_server_connection(newfd));
}

这显然不安全,因为api_server_connection构造函数可能会在将fd赋给其成员变量之前引发异常。

所以我的下一个想法是将accept移动到构造函数中。问题是我真的希望api_server_connection不知道fd来自哪里。例如。如果我想在将来支持inetd,它也可以像fd 0一样传入程序。

那我该怎么做呢我应该为每种方式使用不同的构造函数来获得fd吗?我应该制作子类吗?另一个选择可能是有一个lambda函数吗?

或者我应该捕获任何错误并在那种情况下关闭调用者中的fd?

2 个答案:

答案 0 :(得分:4)

暂时忽略插座,你通常想要做的是将事情分为两个阶段。

在第一阶段,你会做可能抛出的事情,但是如果他们这样做,你可以将系统恢复到一个理智的状态(最好是状态,好像什么都没发生一样)。

在第二阶段,你会做一些你可能无法撤消的事情,但你肯定知道永远不会撤消。

要做到这一点,你需要确定什么可以/将要抛出,以及(特别是)对至少一些相当具体的操作的保证,这些操作根本不会抛出(例如,交换两个项目)。

为了实现这一点,您通常希望在dtor中恢复到理智状态,因此如果抛出异常,析构函数将自动清理。

不幸的是,对于您的特定代码/情况,很难说更多,因为我们根本不了解您正在使用的类。

答案 1 :(得分:0)

首先,为了使用RAII,你必须以面向对象的方式思考。所以我看到你试图用c ++实现服务器类。在这种情况下,您将仅将RAII用于服务器初始化,这意味着您将编写代码并在服务器开始侦听端口时完成该代码。构造函数中的最后一个函数调用必须是listen或start connections thread。之后,您必须实现将处理客户端连接的第二个线程。第二个线程将调用accept以接受客户端,并在服务器工作时进行迭代。在析构函数中,您只需要将侦听标志设置为false并等待接受线程在关闭所有套接字后终止。