在循环内使用 UDP 套接字时连接被拒绝
Connection refused when using a UDP socket inside a loop
考虑以下 MWE class foo
,它有一个 send
成员函数,允许通过 UDP 将字符串发送到端口 1337 上的环回地址:
头文件:foo.h
#include <boost/asio.hpp>
class foo
{
public:
foo(); // Constructor.
void send(std::string const& message);
private:
boost::asio::io_service ios;
boost::asio::ip::udp::socket sock;
boost::asio::ip::udp::endpoint endp;
};
执行文件:foo.cc
#include "foo.h"
foo::foo() : sock{ios}, endp{boost::asio::ip::address::from_string("127.0.0.1"), 1337}
{
sock.connect(endp);
}
void foo::send(std::string const& message)
{
sock.send(boost::asio::buffer(message));
}
现在我想使用 foo
class 将字符串 Hello, World!\n
发送给自己。因此,在主函数中,我实例化了一个 foo
对象,然后我使用 for 循环调用了 foo.send()
5 次(两次爆发之间等待 1 秒)。
主要功能:
#include "foo.h"
#include <iostream>
#include <chrono>
#include <thread>
int main(int argc, char* argv[])
{
foo foo;
for(int i = 0; i<5; i++)
{
foo.send("Hello, World!\n");
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Done" << std::endl;
return 0;
}
代码编译成功。但是,在运行时程序崩溃并抛出以下错误:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): send: Connection refused
Aborted (`core' dumped)
Connection refused
错误消息非常混乱,因为 UDP 在设计上是无连接的。所以无论收件人是否正在收听,程序都应该发送 5 条 UDP 消息。
我做错了什么?
UDP is connectionless by design. So the program should send 5 UDP messages whether the recipient is listening or not.
第一个不代表第二个。使用 UDP,不能保证错误报告,这与保证不报告错误有很大不同。通常,到达没有侦听器的端口的数据包将触发 ICMP 端口不可达消息返回给发送方,并且套接字 API 的大多数实现将在下一次尝试传输到同一个目的地。使用环回,检测错误对于网络堆栈来说更加容易。
考虑以下 MWE class foo
,它有一个 send
成员函数,允许通过 UDP 将字符串发送到端口 1337 上的环回地址:
头文件:foo.h
#include <boost/asio.hpp>
class foo
{
public:
foo(); // Constructor.
void send(std::string const& message);
private:
boost::asio::io_service ios;
boost::asio::ip::udp::socket sock;
boost::asio::ip::udp::endpoint endp;
};
执行文件:foo.cc
#include "foo.h"
foo::foo() : sock{ios}, endp{boost::asio::ip::address::from_string("127.0.0.1"), 1337}
{
sock.connect(endp);
}
void foo::send(std::string const& message)
{
sock.send(boost::asio::buffer(message));
}
现在我想使用 foo
class 将字符串 Hello, World!\n
发送给自己。因此,在主函数中,我实例化了一个 foo
对象,然后我使用 for 循环调用了 foo.send()
5 次(两次爆发之间等待 1 秒)。
主要功能:
#include "foo.h"
#include <iostream>
#include <chrono>
#include <thread>
int main(int argc, char* argv[])
{
foo foo;
for(int i = 0; i<5; i++)
{
foo.send("Hello, World!\n");
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Done" << std::endl;
return 0;
}
代码编译成功。但是,在运行时程序崩溃并抛出以下错误:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): send: Connection refused
Aborted (`core' dumped)
Connection refused
错误消息非常混乱,因为 UDP 在设计上是无连接的。所以无论收件人是否正在收听,程序都应该发送 5 条 UDP 消息。
我做错了什么?
UDP is connectionless by design. So the program should send 5 UDP messages whether the recipient is listening or not.
第一个不代表第二个。使用 UDP,不能保证错误报告,这与保证不报告错误有很大不同。通常,到达没有侦听器的端口的数据包将触发 ICMP 端口不可达消息返回给发送方,并且套接字 API 的大多数实现将在下一次尝试传输到同一个目的地。使用环回,检测错误对于网络堆栈来说更加容易。