为什么 ASIO 套接字的 open() 操作会失败呢?

huangapple go评论73阅读模式
英文:

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()更不可能失败,以及
  • 如果它失败了,最有可能的原因是耗尽了文件描述符

...对我来说都是合理的。

对于acceptoropen也是一样的。

英文:

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.

huangapple
  • 本文由 发表于 2023年7月20日 17:33:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728529.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定