UDP 客户端池发送但不接收
UDP clients pool sending but not receiving
我正在创建一个 udp 客户端池。服务器将是不同计算机中的一些其他应用程序运行,并且它们应该从一开始就处于活动状态。使用可配置文件(示例中的问题不重要,因此不包括在内)创建一对多客户端,以便它们以双向方式连接到这些服务器(1 对 1 关系),发送和接收。
发送可以是同步的,因为它使用小消息,在那里阻塞不是问题,但接收必须是异步的,因为回复可能在发送后很晚才到达。
在我只有一个sockect的测试中,它能够发送,但它根本收不到任何东西。
Q1:问题出在哪里,如何解决?
Q2:我还想知道在异步调用中使用来自 std::vector
的迭代器是否会在新连接由于其在内存中的重新排列而被推入 vector 时出现问题。这可能是个问题?
Q3:我真的不明白为什么在所有示例中发送方和接收方端点(示例中的 endpoint1 和 endpoint2 struct Socket
)都不同,难道它们不能相同吗?
下一个是我的代码:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
class Pool
{
struct Socket {
std::string id;
udp::socket socket;
udp::endpoint endpoint1;
udp::endpoint endpoint2;
enum { max_length = 1024 };
std::array<char, max_length> data;
};
public:
void create(const std::string& id, const std::string& host, const std::string& port)
{
udp::resolver resolver(io_context);
sockets.emplace_back(Socket{ id, udp::socket{io_context, udp::v4()}, *resolver.resolve(udp::v4(), host, port).begin() });
receive(id);
}
void send(const std::string& id, const std::string& msg)
{
auto it = std::find_if(sockets.begin(), sockets.end(), [&](auto& socket) { return id == socket.id; });
if (it == sockets.end()) return;
it->data = std::array<char, Socket::max_length>{ 'h', 'e', 'l', 'l', 'o' };
auto bytes = it->socket.send_to(boost::asio::buffer(it->data, 5), it->endpoint1);
}
void receive(const std::string& id)
{
auto it = std::find_if(sockets.begin(), sockets.end(), [&](auto& socket) { return id == socket.id; });
if (it == sockets.end()) return;
it->socket.async_receive_from(
boost::asio::buffer(it->data, Socket::max_length),
it->endpoint2,
[this, id](boost::system::error_code error, std::size_t bytes) {
if (!error && bytes)
bool ok = true;//Call to whatever function
receive(id);
}
);
}
void poll()
{
io_context.poll();
}
private:
boost::asio::io_context io_context;
std::vector<Socket> sockets;
};
int main()
{
Pool clients;
clients.create("ID", "localhost", "55000");
while (true) {
clients.poll();
clients.send("ID", "x");
Sleep(5000);
}
}
Q1: Where is the problem and how to fix it?
你并没有真正绑定到任何端口,然后你有多个套接字都接收未绑定的 udp 数据包。可能他们只是在竞争,在混乱中迷失了一些东西。
Q2: can std::vector be problematic
是的。使用 std::deque
(稳定 iterator/references 只要你在两端只有 push/pop)。否则,请考虑 std::list
或其他基于节点的容器。
在你的情况下 map<id, socket>
似乎更直观。
实际上,map<endpoint, peer>
会更直观。或者...您完全可以没有同龄人。
Q3: I really does not understand why in all examples sender and
receiver endpoints (endpoint1 and endpoint2 in example struct Socket)
are different, couldn't they be the same?
是的,如果您不关心覆盖您发送到的原始端点,它们可能是“相同的”。
这是我的简化版。正如其他人所说,在同一端点上“侦听”许多 UDP 套接字并不是 possible/useful。也就是说,前提是您甚至绑定到端点。
所以我的示例使用单个 _socket
和本地端点 :8765.
它可以连接到许多客户端端点 - 为了简单起见,我选择用端点本身替换 id 字符串。随意添加一个 map<string, endpoint>
进行一些翻译。
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
#include <set>
using boost::asio::ip::udp;
using namespace std::chrono_literals;
class Pool {
public:
using Message = std::array<char, 1024>;
using Peers = std::set<udp::endpoint>;
using Id = udp::endpoint;
Pool() { receive_loop(); }
Id create(const std::string& host, const std::string& port)
{
auto ep = *udp::resolver(_io).resolve(udp::v4(), host, port).begin();
/*auto [it,ok] =*/_peers.emplace(ep);
return ep;
}
void send(Id id, const std::string& msg)
{
/*auto bytes =*/
_socket.send_to(boost::asio::buffer(msg), id);
}
void receive_loop()
{
_socket.async_receive_from(
boost::asio::buffer(_incoming), _incoming_ep,
[this](boost::system::error_code error, std::size_t bytes) {
if (!error && bytes)
{
if (_peers.contains(_incoming_ep)) {
std::cout << "Received: "
<< std::quoted(std::string_view(
_incoming.data(), bytes))
<< " from " << _incoming_ep << "\n";
} else {
std::cout << "Ignoring message from unknown peer "
<< _incoming_ep << "\n";
}
}
receive_loop();
});
}
void poll() { _io.poll(); }
private:
boost::asio::io_context _io;
udp::socket _socket{_io, udp::endpoint{udp::v4(), 8765}};
Message _incoming;
udp::endpoint _incoming_ep;
Peers _peers;
};
int main(int argc, char** argv) {
Pool pool;
std::vector<Pool::Id> peers;
for (auto port : std::vector(argv + 1, argv + argc)) {
peers.push_back(pool.create("localhost", port));
}
int message_number = 0;
while (peers.size()) {
pool.poll();
auto id = peers.at(rand() % peers.size());
pool.send(id, "Message #" + std::to_string(++message_number) + "\n");
std::this_thread::sleep_for(1s);
}
}
在我的机器上使用一些模拟的遥控器,例如
sort -R /etc/dictionaries-common/words | while read word; do sleep 5; echo "$word"; done | netcat -u -l -p 8787 -w 1000
还从“其他”端点发送虚假消息以模拟 stray/unknown 消息。
我正在创建一个 udp 客户端池。服务器将是不同计算机中的一些其他应用程序运行,并且它们应该从一开始就处于活动状态。使用可配置文件(示例中的问题不重要,因此不包括在内)创建一对多客户端,以便它们以双向方式连接到这些服务器(1 对 1 关系),发送和接收。
发送可以是同步的,因为它使用小消息,在那里阻塞不是问题,但接收必须是异步的,因为回复可能在发送后很晚才到达。
在我只有一个sockect的测试中,它能够发送,但它根本收不到任何东西。
Q1:问题出在哪里,如何解决?
Q2:我还想知道在异步调用中使用来自 std::vector
的迭代器是否会在新连接由于其在内存中的重新排列而被推入 vector 时出现问题。这可能是个问题?
Q3:我真的不明白为什么在所有示例中发送方和接收方端点(示例中的 endpoint1 和 endpoint2 struct Socket
)都不同,难道它们不能相同吗?
下一个是我的代码:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
class Pool
{
struct Socket {
std::string id;
udp::socket socket;
udp::endpoint endpoint1;
udp::endpoint endpoint2;
enum { max_length = 1024 };
std::array<char, max_length> data;
};
public:
void create(const std::string& id, const std::string& host, const std::string& port)
{
udp::resolver resolver(io_context);
sockets.emplace_back(Socket{ id, udp::socket{io_context, udp::v4()}, *resolver.resolve(udp::v4(), host, port).begin() });
receive(id);
}
void send(const std::string& id, const std::string& msg)
{
auto it = std::find_if(sockets.begin(), sockets.end(), [&](auto& socket) { return id == socket.id; });
if (it == sockets.end()) return;
it->data = std::array<char, Socket::max_length>{ 'h', 'e', 'l', 'l', 'o' };
auto bytes = it->socket.send_to(boost::asio::buffer(it->data, 5), it->endpoint1);
}
void receive(const std::string& id)
{
auto it = std::find_if(sockets.begin(), sockets.end(), [&](auto& socket) { return id == socket.id; });
if (it == sockets.end()) return;
it->socket.async_receive_from(
boost::asio::buffer(it->data, Socket::max_length),
it->endpoint2,
[this, id](boost::system::error_code error, std::size_t bytes) {
if (!error && bytes)
bool ok = true;//Call to whatever function
receive(id);
}
);
}
void poll()
{
io_context.poll();
}
private:
boost::asio::io_context io_context;
std::vector<Socket> sockets;
};
int main()
{
Pool clients;
clients.create("ID", "localhost", "55000");
while (true) {
clients.poll();
clients.send("ID", "x");
Sleep(5000);
}
}
Q1: Where is the problem and how to fix it?
你并没有真正绑定到任何端口,然后你有多个套接字都接收未绑定的 udp 数据包。可能他们只是在竞争,在混乱中迷失了一些东西。
Q2: can std::vector be problematic
是的。使用 std::deque
(稳定 iterator/references 只要你在两端只有 push/pop)。否则,请考虑 std::list
或其他基于节点的容器。
在你的情况下 map<id, socket>
似乎更直观。
实际上,map<endpoint, peer>
会更直观。或者...您完全可以没有同龄人。
Q3: I really does not understand why in all examples sender and receiver endpoints (endpoint1 and endpoint2 in example struct Socket) are different, couldn't they be the same?
是的,如果您不关心覆盖您发送到的原始端点,它们可能是“相同的”。
这是我的简化版。正如其他人所说,在同一端点上“侦听”许多 UDP 套接字并不是 possible/useful。也就是说,前提是您甚至绑定到端点。
所以我的示例使用单个 _socket
和本地端点 :8765.
它可以连接到许多客户端端点 - 为了简单起见,我选择用端点本身替换 id 字符串。随意添加一个 map<string, endpoint>
进行一些翻译。
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
#include <set>
using boost::asio::ip::udp;
using namespace std::chrono_literals;
class Pool {
public:
using Message = std::array<char, 1024>;
using Peers = std::set<udp::endpoint>;
using Id = udp::endpoint;
Pool() { receive_loop(); }
Id create(const std::string& host, const std::string& port)
{
auto ep = *udp::resolver(_io).resolve(udp::v4(), host, port).begin();
/*auto [it,ok] =*/_peers.emplace(ep);
return ep;
}
void send(Id id, const std::string& msg)
{
/*auto bytes =*/
_socket.send_to(boost::asio::buffer(msg), id);
}
void receive_loop()
{
_socket.async_receive_from(
boost::asio::buffer(_incoming), _incoming_ep,
[this](boost::system::error_code error, std::size_t bytes) {
if (!error && bytes)
{
if (_peers.contains(_incoming_ep)) {
std::cout << "Received: "
<< std::quoted(std::string_view(
_incoming.data(), bytes))
<< " from " << _incoming_ep << "\n";
} else {
std::cout << "Ignoring message from unknown peer "
<< _incoming_ep << "\n";
}
}
receive_loop();
});
}
void poll() { _io.poll(); }
private:
boost::asio::io_context _io;
udp::socket _socket{_io, udp::endpoint{udp::v4(), 8765}};
Message _incoming;
udp::endpoint _incoming_ep;
Peers _peers;
};
int main(int argc, char** argv) {
Pool pool;
std::vector<Pool::Id> peers;
for (auto port : std::vector(argv + 1, argv + argc)) {
peers.push_back(pool.create("localhost", port));
}
int message_number = 0;
while (peers.size()) {
pool.poll();
auto id = peers.at(rand() % peers.size());
pool.send(id, "Message #" + std::to_string(++message_number) + "\n");
std::this_thread::sleep_for(1s);
}
}
在我的机器上使用一些模拟的遥控器,例如
sort -R /etc/dictionaries-common/words | while read word; do sleep 5; echo "$word"; done | netcat -u -l -p 8787 -w 1000
还从“其他”端点发送虚假消息以模拟 stray/unknown 消息。