简体   繁体   English

可能 boost::asio::ip::udp::socket::send_to 甚至失败?

[英]May boost::asio::ip::udp::socket::send_to even fail?

Please consider following code snippet.请考虑以下代码片段。

It first resolves address of remote host, then opens socket and sends some data to it.它首先解析远程主机的地址,然后打开套接字并向其发送一些数据。 Note, it throws immediately when error occurs.请注意,发生错误时它会立即抛出。

No concurrency involved.不涉及并发。 Message fits to 1K.消息适合 1K。 Basically the only difference between this code snippet and "real" code is following: message may be sent in several seconds after endpoint was resolved and socket is opened.基本上,此代码段和“真实”代码之间的唯一区别如下:在解决端点并打开套接字后几秒钟内可能会发送消息。

using namespace boost::asio;
io_context io_context;

ip::udp::resolver resolver{io_context};
const auto endpoints = resolver.resolve(ip::udp::v4(), "host", "port");
if (endpoints.empty())
    throw std::runtime_error("No endpoints found");
const auto endpoint = endpoints->endpoint();

ip::udp::socket socket{io_context};
socket.open(ip::udp::v4());

const auto message = buffer("asdf"); // fits to 1K

// may the line below fail provided the code above is executed successfully?
socket.send_to(message, endpoint);

For me, provided the endpoint is valid and socket is opened successfully, it seems that call to socket.send_to should be always successful, even if remote host becomes unavailable (since UDP is used).对我来说,只要端点有效并且套接字已成功打开,似乎对socket.send_to的调用应该总是成功的,即使远程主机不可用(因为使用了 UDP)。

  1. What exceptions should I expect in the last line?最后一行应该有哪些例外?
  2. Can I just assume that no errors will appear?我可以假设不会出现错误吗?
  3. Should I expect any IO related error code there since we are doing IO anyway?我应该期待任何与 IO 相关的错误代码,因为我们正在做 IO 吗?

ASIO implements this in terms of underlying operating system calls. ASIO 在底层操作系统调用方面实现了这一点。 On POSIX, that would be sendto .在 POSIX 上,这将是sendto The possible error conditions are documented (see below).记录了可能的错误情况(见下文)。

However, first things first:但是,首先要做的是:


You could receive a segfault for addressing out of bounds into unknown address space.您可能会收到一个段错误,用于越界寻址到未知地址空间。 Depending on your platform it might manifest as EFAULT ( boost::asio::error::fault ).根据您的平台,它可能表现为EFAULT ( boost::asio::error::fault )。

const_buffer buffer{"asdf", 10};

The preferred spelling here is:这里的首选拼写是:

auto buffer = boost::asio::buffer("asdf"); // char[5] includes NUL

Which will send the char[] (including terminating NUL character) (see overload ).它将发送char[] (包括终止 NUL 字符)(请参阅重载)。 If you don't want that, consider eg boost::asio::buffer("asdf"sv) , which uses a string view, without you having to call strlen .如果您不希望这样,请考虑使用字符串视图的boost::asio::buffer("asdf"sv) ,而无需调用strlen

Note how you create naming conflicts where buffer hides boost::asio::buffer because of using namespace .请注意,由于using namespacebuffer隐藏boost::asio::buffer时如何创建命名冲突。 You did the same with io_context .你对io_context做了同样的事情。 I'd advise against this level of flirting with danger in C++我建议不要在 C++ 中进行这种程度的危险调情

Other Notes其他注意事项

if (ec)
    throw std::system_error(ec);

Is not needed.不需要。 If you don't supply ec , the exception boost::system::system_error (but from boost) will already be raised in the same fashion.如果您不提供ec ,异常boost::system::system_error (但来自 boost)将以相同的方式引发。

size_t sent = socket.send_to(
        ba::buffer("asdf"),
        endpoints->endpoint());

You use endpoints->endpoint() without validating the resolver results.您使用endpoints->endpoint()而不验证解析器结果。 Depending on situation zero or more resolutions might exist.根据情况,可能存在零个或多个分辨率。 You might be dereferencing an invalid iterator.您可能正在取消引用无效的迭代器。 This, again, can cause error conditions.这同样会导致错误情况。

Other Error Codes其他错误代码

You can get inspiration from the POSIX documentation: https://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html您可以从 POSIX 文档中获得灵感: https://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html

The vast majority of the conditions are not applicable, partly due to it绝大多数条件不适用,部分原因是它

  • being datagram, not stream protocol是数据报,不是 stream 协议
  • the socket not being in non-blocking mode here (or that being abstracted away by ASIO)套接字在这里没有处于非阻塞模式(或者被 ASIO 抽象出来)
  • the socket being "known good" (assuming no concurrent code that you didn't show)套接字“已知良好”(假设没有您未显示的并发代码)

However a few remain:但是仍然有一些:

  • EACCESS can occur if you use a regular endpoint as if it were multicast如果您像多播一样使用常规端点,则可能会发生EACCESS
  • EDESTADDRREQ if you pass an invalid endpoint (eg default constructed) EDESTADDRREQ如果你传递了一个无效的端点(例如默认构造)
  • EINTR unless you have signals ignored EINTR除非您忽略了信号
  • ENOBUFS (when the adapter is jammed - doesn't happen on linux where packets are just dropped) ENOBUFS (当适配器卡住时 - 不会发生在刚刚丢弃数据包的 linux 上)

Depending on the actual arguments in your real code:根据实际代码中的实际 arguments :

  • EMSGSIZE if your buffer exceeds the limit that can be sent atomically EMSGSIZE如果您的缓冲区超过了可以自动发送的限制
  • EOPNOTSUPP if you pass invalid flags EOPNOTSUPP如果您传递无效标志

SUMMARY概括

The real question is: do you anticipate any errors that you should deal with?真正的问题是:您是否预计应该处理任何错误? If not simply accept the exceptions (I suggest not passing error_code parameters).如果不是简单地接受异常(我建议不要传递error_code参数)。

The only such condition I can think of is a failure to resolve the hostname.我能想到的唯一这样的情况是无法解析主机名。 However, a quick test tells me the resultset will not be empty, but instead resolve throws Host not found (authoritative) .但是,快速测试告诉我结果集不会为空,而是resolve抛出Host not found (authoritative)

So, just simplify:因此,只需简化:

Live On Coliru住在科利鲁

#include <boost/asio.hpp>

using namespace std::literals;
namespace ba = boost::asio;
using ba::ip::udp;

int main() {
    ba::io_context io;
    udp::resolver resolver{io};
    auto endpoints = resolver.resolve(udp::v4(), "127.0.0.1", "6767");

    udp::socket socket{io};
    socket.open(udp::v4());

    return socket.send_to(ba::buffer("asdf"sv), endpoints->endpoint());
}

With

nc -u -l -p 6767 & sleep 1; ./a.out

Prints印刷

asdf

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM