英文:
Why would ASIO socket open() ever fail?
问题
当使用ASIO连接套接字时,需要执行以下步骤:(1) 创建套接字;(2) 打开它;(3) 连接它。
boost::asio::io_context io_context;
// (1) 创建套接字
boost::asio::ip::tcp::socket socket(io_context);
// (2) 打开它
boost::system::error_code open_error;
socket.open(open_error);
if (open_error) { /* .... */ }
// (3) 连接
boost::system::error_code connect_error;
boost::asio::ip::tcp::endpoint endpoint(
boost::asio::ip::address::from_string("1.2.3.4"), 12345);
socket.connect(endpoint, connect_error);
if (connect_error) { /* .... */ }
很明显,connect()
调用可能会失败。这是一个真正的网络操作,远程端点可能无法访问,或者拒绝连接等。
但是 open()
调用是否可能失败呢?如果可能,是什么原因导致的呢?它似乎没有做太多事情,当然不会访问网络。我认为如果进程的文件描述符用尽了,可能会导致 open()
失败 - 这样说对吗?
对于传递给 acceptor.accept()
的套接字而言,一个类似的问题也适用于 acceptor
类本身:在调用其 accept()
方法之前,您必须打开它。那么它是否可能失败呢?
(对于套接字和接收器,也可以在构造函数中作为参数传入进行打开。但是文档中提到它们可能会引发异常,因此相同的问题仍然适用。)
英文:
When connecting to a socket with ASIO, you need to (1) create the socket; (2) open()
it; (3) connect()
it.
boost::asio::io_context io_context;
// (1) create socket
boost::asio::ip::tcp::socket socket(io_context);
// (2) open it
boost::system::error_code open_error;
socket.open(open_error);
if (open_error) { /* .... */ }
// (3) connect
boost::system::error_code connect_error;
boost::asio::ip::tcp::endpoint endpoint(
boost::asio::ip::address::from_string("1.2.3.4"), 12345);
socket.connect(endpoint, connect_error);
if (connect_error) { /* .... */ }
It's pretty clear that the connect()
call could fail. It's an actual networking operation, and the remote endpoint might be inaccessible, or refuse the connection, etc.
But can the open()
call fail? If so, what would cause that? It doesn't seem to do much, and certainly not access the network. I think perhaps if the process is out of file descriptors then that could cause it to fail - does that seem right?
A similar question applies to sockets passed to acceptor.accept()
instead of connecting outbound. More to the point it applies to the acceptor
class itself: you have to open it before calling its accept()
method. Can that fail?
(For both sockets and acceptors it's possible to open as part of the constructor by passing in the relevant parameters. But then the documentation says that they can throw an exception, so the same question still applies.)
答案1
得分: 3
Boost.Asio文档确实没有明确指定open()
可能以哪些方式失败,只说明了它可能失败。然而,它确实有一个表格,显示了Boost.Asio低级套接字API的哪些部分映射到BSD套接字API的哪些部分:对于POSIX系统和Windows系统,ip::tcp::socket::open
对应于socket()
函数,因此我们可以假设它可能因为socket()
可能失败的原因而失败。
在POSIX中,如果不支持地址族、协议或套接字类型(对于TCP来说不太可能),或者没有可用的文件描述符,socket()
将失败。如果缺少特权或内存不足,它可能会失败(参考链接:https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)。Windows的socket()
函数具有类似的错误条件,还有一些Windows特定的错误条件(参考链接:https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket)。
你的假设...
- 这比
connect()
更不可能失败,以及 - 如果它失败了,最有可能的原因是耗尽了文件描述符
...对我来说都是合理的。
对于acceptor
的open
也是一样的。
英文:
The Boost.Asio docs indeed do not specify in which ways open()
can fail, only that it can fail. However, it does have a table that shows which parts of the Boost.Asio low-level socket API map to which parts of the BSD socket API: for both POSIX systems and Windows systems, ip::tcp::socket::open
corresponds to the socket()
function, so we can assume that it can fail for at least the reasons for which socket()
can fail.
In POSIX, socket()
shall fail if the address family, protocol or socket type are not supported (unlikely for TCP), or if there are no file descriptors available. It may fail if you lack privileges or have run out of memory (reference). The socket()
function for Windows has similar error conditions plus some Windows-specific ones (reference).
Your assumptions...
- that this is less likely to fail than
connect()
, and - that if it does fail, the most likely cause is running out of file descriptors
...both sound reasonable to me.
The same holds for acceptor
's open
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论