我正在使用asio库(C++),我想创建一对服务器/客户端,以便:
- 服务器正在某个端口上传输数据;
- 客户端连接到该端口并接收此类数据。
现在,在通常的客户端/服务器应用程序中,服务器正在“监听”某个端口,而客户端则连接到该端口。在我上面描述的内容中,似乎部分已切换,因此我设法为服务器编写以下代码:
#include <iostream>
#include <numeric>
#include <vector>
#include "asio.hpp"
int main() {
constexpr int size = 10;
std::vector<int> vct(size);
std::iota(vct.begin(), vct.end(), 0);
asio::io_context context;
asio::ip::udp::resolver resolver{context};
asio::ip::udp::socket socket{context};
socket.open(asio::ip::udp::v4());
socket.connect(asio::ip::udp::endpoint(asio::ip::udp::v4(), 10888));
size_t len = socket.send(asio::buffer(vct));
std::cout << "Sent " << len << " b." << std::endl;
return EXIT_SUCCESS;
}
以及为客户端提供的以下内容:
#include <iostream>
#include <vector>
#include "asio.hpp"
int main()
{
constexpr int size = 10;
std::vector<int> vct(size);
asio::io_context context;
asio::ip::udp::endpoint local_endpoint{asio::ip::address::from_string("127.0.0.1"), 10888};
asio::ip::udp::endpoint sender_endpoint;
asio::ip::udp::socket socket{context};
socket.open(asio::ip::udp::v4());
socket.bind(local_endpoint);
size_t len = socket.receive_from(asio::buffer(vct), sender_endpoint);
std::cout << "Received " << len << " b from " << sender_endpoint << std::endl;
for (auto i : vct)
std::cout << i << std::endl;
return EXIT_SUCCESS;
}
所以我在服务器中使用connect
,而在客户端中使用bind
。即使这看起来有效,这也让我有点不安。
我的问题是
- 这是设置“流媒体服务器”和接收器的正确方法吗(让我们暂时放弃有关异步的问题,我指的是连接级别)
bind
和connect
应该这样使用吗?
最佳答案
目前还不清楚什么“让你有点不安”。
你的意思是你想互换角色吗?对于客户端来说,连接到知名发件人确实具有更传统的意义。
我同意这是广播情况。令人惊讶的是,网络上的例子很少。我怀疑它可能会变得更复杂,但下面将是一个使您的程序正常运行的简单示例。
简化
首先,我将您的发送者/接收者合并到同一个源中:
<强> Live On Coliru
#include <boost/asio.hpp>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <numeric>
namespace asio = boost::asio;
using asio::ip::udp;
template <> struct fmt::formatter<udp::endpoint> : ostream_formatter {};
int main(int argc, char**) {
constexpr int size = 10;
std::vector<int> vct(size);
asio::io_context context;
udp::socket socket{context};
socket.open(udp::v4());
if (argc > 1) { // sender
socket.connect({{}, 10888});
for (int i : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
iota(begin(vct), end(vct), size * i);
size_t len = socket.send(asio::buffer(vct));
fmt::print("Sent #{}, {}b, vct {}\n", i, len, vct);
}
socket.send(asio::buffer(vct, 0));
} else { // receiver
socket.bind({{}, 10888});
udp::endpoint sender_endpoint;
while (size_t len = socket.receive_from(asio::buffer(vct), sender_endpoint))
fmt::print("Received {}b from {}, vct {}\n", len, sender_endpoint, vct);
}
fmt::print("Bye\n");
}
输出有点困惑,所以为了清楚起见,将其放在我的盒子上:
广播:交换发送者/接收者
鱼与熊掌兼得。我们确保发送到广播地址,并将客户端绑定(bind)到该地址:
<强> Live On Coliru
#include <boost/asio.hpp>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <numeric>
namespace asio = boost::asio;
using asio::ip::udp;
template <> struct fmt::formatter<udp::endpoint> : ostream_formatter {};
int main(int argc, char**) {
constexpr int size = 10;
std::vector<int> vct(size);
asio::io_context context;
udp::socket socket{context};
socket.open(udp::v4());
udp::endpoint ep{asio::ip::address_v4::broadcast(), 10888};
if (argc > 1) { // sender
socket.set_option(udp::socket::reuse_address(true));
socket.set_option(udp::socket::broadcast(true));
for (int i : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
iota(begin(vct), end(vct), size * i);
auto len = socket.send_to(asio::buffer(vct), ep);
fmt::print("Sent #{}, {}b, vct {}\n", i, len, vct);
}
socket.send_to(asio::buffer(vct, 0), ep);
} else { // receiver
socket.bind(ep);
udp::endpoint sender_endpoint;
while (size_t len = socket.receive_from(asio::buffer(vct), sender_endpoint))
fmt::print("Received {}b from {}, vct {}\n", len, sender_endpoint, vct);
}
fmt::print("Bye\n");
}
再次直播:
关于c++ - asio 和 "streaming server",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76257764/