【问题标题】:Windows boost asio: 10061 in async_receive_from on on async_send_toWindows boost asio:async_receive_from 中的 10061 on on async_send_to
【发布时间】:2012-12-21 19:10:20
【问题描述】:

我有一个相当大的应用程序,可以在 Linux 上按需要运行。我最近在 Windows 7 上使用 VC2012 和 boost asio 1.52 编译它并遇到了一个奇怪的问题:

在同一 UDP 套接字上的 async_receive_from 后跟 async_send_to 会导致使用 boost::system::error_code 10061 调用读取完成处理程序:

由于目标机器主动拒绝,无法建立连接

如果发送目的地是本地主机上的另一个端口。如果数据包被发送到另一台机器,则不会调用读取完成处理程序。在读完成处理程序之后,调用写完成处理程序没有错误。

以下代码复制了该问题:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

using namespace std;
using namespace boost::asio;

void read_completion_handler(const boost::system::error_code& ec, std::size_t bytes_received)
{
  if (!ec)
    cout << "Received " << bytes_received << " successfully" << endl;
  else
    cout << "Error: " << ec.message() << endl;
}

void write_completion_handler(const boost::system::error_code& ec, std::size_t bytes_transferred)
{
  if (!ec)
    cout << "Wrote " << bytes_transferred << " successfully" << endl;
  else
    cout << "Error: " << ec.message() << endl;
}

int main(int argc, char** argv)
{
  enum
  {
    max_length = 1500,
    out_length = 100
  };
  // buffer for incoming data
  char data[max_length];
  // outgoing data
  char out_data[out_length];

  // sender endpoint
  ip::udp::endpoint sender_endpoint;
  // for sending packets: if this localhost, the error occurs
  ip::udp::endpoint destination(ip::address::from_string("127.0.0.1"), 5004);

  io_service ioService;
  ip::udp::socket socket(ioService, ip::udp::endpoint(ip::udp::v4(), 49170));

  socket.async_receive_from(
    buffer(data, max_length), sender_endpoint,
    boost::bind(&read_completion_handler, 
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred));

  socket.async_send_to( boost::asio::buffer(out_data, out_length),
    destination,
    boost::bind(&write_completion_handler,
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred));

  ioService.run();

  cout << "Done" << endl;
  return 0;
}

在 linux 上,这从来都不是问题。有人有解释吗?据我所知,在同一个套接字上同时读写应该是可以的,或者在 Windows 上不是这样吗?如果 localhost 是目的地,为什么会改变行为?

【问题讨论】:

    标签: windows network-programming udp boost-asio


    【解决方案1】:

    是的,在您提出这个问题后大约 6 个月。我什至不确定我是怎么来到这里的。我自己也遇到过这个问题——但好消息是这不是问题。

    当某些机器未侦听您将消息发送到的端口时,它们会通过 ICMP 返回目标不可达消息。 Asio 将其转换为 boost::system::errc::connection_refused 和/或 boost::system::errc::connection_reset。这是一个毫无意义的错误,因为 UDP 是无连接的。您可以放心地在您的 async_receive_from 处理程序中忽略这两个错误代码(即,如果您返回其中一个错误,只需再次调用 async_receive_from)。

    【讨论】:

    • 您好,感谢您的回复和解释 asio 错误代码翻译。那讲得通。很高兴知道其他人遇到了类似的问题。不过,对我来说不太清楚的是为什么写入导致读取失败?这是一个asio错误吗?你能解释一下吗?
    • 您好! 2年后,我找到了你的线索。我遇到了同样的问题!当主机(通常在同一台机器 127.0.0.1 上)尝试发送数据并且该端口上没有任何东西可以监听它时,UDP 似乎会做这种事情。发生在 C# 以及 Boost::Asio C++ 中。要在 C# 中解决此问题,您可以编写以下代码: byte[] byteTrue = new byte[4]; byteTrue[byteTrue.Length - 1] = 1; m_udpClient.Client.IOControl(-1744830452, byteTrue, null);抱歉,我还不知道 Boost Asio 的解决方案,所以只需做一个特殊情况并忽略该错误
    • Niether boost::system::errc::connection_refused pr case boost::system::errc::connection_reset are = 10061
    【解决方案2】:

    对于遇到此问题的任何人,请阅读我在上面对第一个回复所做的评论。

    但是,如果您通过任何更改在 C# 中遇到相同的问题,请使用此代码来消除该行为:

            byte[] byteTrue = new byte[4];
            byteTrue[byteTrue.Length - 1] = 1;
            m_udpClient.Client.IOControl(-1744830452, byteTrue, null);
    

    【讨论】:

      【解决方案3】:

      要在 UDP 接收时禁用 ICMP PORT_UNREACHABLE,请将 SIO_UDP_CONNRESET 设置为 0(不是 1,就像其他答案所建议的那样):

      #ifdef _WIN32
          struct winsock_udp_connreset {
            unsigned long value = 0;
            int name() { return -1744830452; /* SIO_UDP_CONNRESET */ }
            unsigned long* data() { return &value; }
          };
          winsock_udp_connreset connreset{0};
          socket.io_control(connreset);
      #endif
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-06
        • 1970-01-01
        • 2017-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多