我有一个相当大的应用程序,可以在Linux上运行。我最近使用VC2012在Windows 7上编译并使用了增强asio 1.52并遇到了一个奇怪的问题:
async_receive_from
后跟同一个UDP套接字上的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是目的地,为什么行为会发生变化?
答案 0 :(得分:5)
是的,在您提出此问题后约6个月。我甚至不确定我是怎么来到这里的。我自己遇到了这个问题 - 但好消息是这不是问题。
有些计算机在没有收听您发送邮件的端口时,会通过ICMP返回“目标无法访问”消息。 Asio将其转换为boost :: system :: errc :: connection_refused和/或boost :: system :: errc :: connection_reset。这是一个毫无意义的错误,因为UDP是无连接的。您可以安全地忽略async_receive_from处理程序中的这两个错误代码(即,如果您返回其中一个错误,只需再次调用async_receive_from)。
答案 1 :(得分:1)
对于任何绊脚石的人,请阅读我上面对第一个回复所做的评论。
但是,如果您遇到C#中遇到相同问题的任何更改,请使用此代码来消除此行为:
byte[] byteTrue = new byte[4];
byteTrue[byteTrue.Length - 1] = 1;
m_udpClient.Client.IOControl(-1744830452, byteTrue, null);
答案 2 :(得分:0)
要在 UDP 接收上禁用 ICMP PORT_UNREACHABLE
,请将 before they exist 设置为 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