2012-04-26 67 views
1

我是C++的新手(来自C)。我从概念上理解RAII应该如何工作,但我无法在其中安装一个简单的套接字连接处理程序。如何使用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其成员变量之前抛出异常。

所以我的下一个想法是将接受移入构造函数。问题是我真的希望api_server_connection对fd来自何处不可知。例如。如果我想在未来支持inetd,那么它可能只是作为fd 0传入程序。

那么,我该如何做到这一点。我应该使用不同的构造函数来获取fd吗?我是否应该制作子类?另一个选择可能是有一个lambda函数?

或者我应该只是在这种情况下发现任何错误并关闭调用者中的fd?

+3

你看过/阅读过关于[Boost ASIO](http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio.html)的工作原理吗? (你有没有考虑完全跳过这个,只是使用ASIO?) – 2012-04-26 19:29:40

+0

'api_server_connection'如何引发异常?您没有向我们显示该代码。 – 2012-04-26 19:30:01

+0

@ R.MartinhoFernandes我还没有写它......但我知道它会有pimpl,这意味着内存分配,这可能会失败。 – 2012-04-26 19:43:59

回答

4

现在忽略,套接字,你通常想要做的是将事情分为两个阶段。

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

在第二阶段,你做的事情,你可能无法撤消,但你肯定知道永远不会抛出。要做到这一点,您需要确保可以抛出什么(特别是)至少一些永远不会抛弃的特定操作(例如,交换两个项目)的某些保证。

为了实现这一点,你通常希望在dtor中恢复到一个健全的状态,所以如果抛出异常,析构函数会自动清理。

不幸的是,很难说更多的关于你的具体代码/情况,因为我们对你正在使用的类不够了解。

+0

我想你确实让我以正确的方式思考,所以我想我应该接受这一点。我将创建一个fd_guard类,并首先将fd放入它,但不能失败。然后我可以无忧地创建连接对象,并让它继承fd或fd_guard。 – 2012-04-26 20:10:47

0

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