在网络库中初始化Winsock的最佳实践



我正在编写一个小型库,该库在内部使用操作系统套接字API进行一些联网。

在Windows上,需要在开始时调用WSAStartup,在结束时调用WSACleanup来初始化Winsock。然而,文档中说,它可以多次初始化Winsock,然后清理相同次数的Winsock,因为它在内部使用引用计数。

现在我正在解决一个难题。对图书馆作家来说,什么是更好的做法?

  1. 提供调用WSAStartup/WSACleanup的全局函数initializeLibrary/terminateLibrary,并指示用户在应用程序开始/结束时调用它们
  2. 在我的类的构造函数/析构函数中内部调用WSAStartup/WSACleanup,根本不用麻烦用户

现在我看到第二个选项看起来更方便,但这是个好主意吗?这样做难道没有任何隐藏的不良后果吗?它能对性能产生影响吗?图书馆秘密这样做是个好做法吗?

库秘密执行此操作是一种好做法吗?

我可能错过了这里的要点,但对我来说,任何库的要点都是从最终用户那里抽象细节,使使用它变得轻松。当然,抽象可能会在一定程度上限制灵活性,但我觉得这里不是这样。请注意,我只是在讨论"保密"问题,老实说,我不知道它是如何影响性能的。

对于库作者来说,什么是更好的做法?

此处缺少第三个选项。我通常反对init()finalize()函数,因为它反对RAII——用户可能会忘记调用它们。但是,您可以设计一个仅在应用程序的"根"处创建的"令牌"类,这是使用API的任何其他部分所必需的。考虑一下:

#include <WinSock2.h>
class ApiKey {
public:
ApiKey() {
auto wsadata = WSADATA();
auto startupResult = WSAStartup(MAKEWORD(2, 2), &wsadata);
// ...
}
~ApiKey() {
auto cleanupResult = WSACleanup();
// ...
}
};
class Socket {
public:
Socket(ApiKey& key) {
}
// ...
};

我不是boost::asio用户,但据我所知,他们就是这么做的。io_context类充当ApiKey

如果你想了解更多信息,你可以在他们的源代码中查找:

https://github.com/boostorg/asio/blob/develop/include/boost/asio/detail/impl/winsock_init.ipp

https://github.com/boostorg/asio/blob/develop/include/boost/asio/io_context.hpp

相关内容

  • 没有找到相关文章

最新更新