c++ - asio 和 "streaming server"

标签 c++ udp boost-asio asio

我正在使用asio库(C++),我想创建一对服务器/客户端,以便:

  1. 服务器正在某个端口上传输数据;
  2. 客户端连接到该端口并接收此类数据。

现在,在通常的客户端/服务器应用程序中,服务器正在“监听”某个端口,而客户端则连接到该端口。在我上面描述的内容中,似乎部分已切换,因此我设法为服务器编写以下代码:

#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。即使这看起来有效,这也让我有点不安。 我的问题是

  1. 这是设置“流媒体服务器”和接收器的正确方法吗(让我们暂时放弃有关异步的问题,我指的是连接级别)
  2. bindconnect 应该这样使用吗?

最佳答案

目前还不清楚什么“让你有点不安”。

你的意思是你想互换角色吗?对于客户端来说,连接到知名发件人确实具有更传统的意义。

我同意这是广播情况。令人惊讶的是,网络上的例子很少。我怀疑它可能会变得更复杂,但下面将是一个使您的程序正常运行的简单示例。

简化

首先,我将您的发送者/接收者合并到同一个源中:

<强> 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");
}

输出有点困惑,所以为了清楚起见,将其放在我的盒子上:

enter image description here

广播:交换发送者/接收者

鱼与熊掌兼得。我们确保发送到广播地址,并将客户端绑定(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");
}

再次直播:

enter image description here

关于c++ - asio 和 "streaming server",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76257764/

相关文章:

c - 奇怪的 udp 套接字 sendto 行为

networking - 用于对大数据传输进行 udp 和 tcp 性能基准测试的实用程序

c++ - 带有 vector 结构的 boost::asio::buffer

c++ - 并行减少(例如求和)hpx::futures<double> 的 vector

ubuntu - 如何在一个UDP数据包中发送大块数据?

boost - 为 Windows Embedded Compact 7 编译 boost 库

c++ - 如何编写连接池?

c++ - 如何使 boost::lockfree::queue 动态调整大小

c++ - 列表<myClass<int> * > 排序

c++ - 使用 Ncurses (C++) 时不打印宽字符