1#include "io/udp_server.hpp"
5namespace roboctrl::io {
6udp_server::udp_server(
const info_type& info) : info_{info}, socket_{roboctrl::
executor()} {
7 if (info.key_.empty())
throw std::invalid_argument(
"empty UDP server key");
9 asio::ip::make_address(info_.address);
12void udp_server::connect() {
13 if (connected_)
return;
14 const endpoint local{asio::ip::make_address(info_.address), info_.port};
15 socket_.open(local.protocol());
20void udp_server::start() {
22 if (!connected_)
throw std::logic_error(
"UDP server start before connect");
27void udp_server::stop() {
28 asio::error_code ignored;
29 socket_.close(ignored);
34awaitable<void> udp_server::send(
const endpoint& peer, byte_span data) {
35 if (!started_)
co_return;
36 if (data.empty() || data.size() > 65507 || peer.port() == 0) {
37 throw std::invalid_argument(
"invalid UDP datagram or peer port");
39 if (queued_bytes_ + data.size() > 65536) {
40 logger::instance().log_warn(
"drop UDP datagram: transmit queue full");
43 queue_.push_back({peer, {data.begin(), data.end()}});
44 queued_bytes_ += data.size();
51awaitable<void> udp_server::send_task() {
52 while (!queue_.empty()) {
53 auto packet = std::move(queue_.front());
55 queued_bytes_ -= packet.data.size();
56 asio::error_code error;
57 const auto sent =
co_await socket_.async_send_to(asio::buffer(packet.data), packet.peer,
58 asio::redirect_error(asio::use_awaitable, error));
59 if (error || sent != packet.data.size()) {
60 logger::instance().log_warn(
"UDP datagram write failed: {}", error.message());
66awaitable<void> udp_server::task() {
69 asio::error_code error;
70 const auto size =
co_await socket_.async_receive_from(asio::buffer(buffer_), source,
71 asio::redirect_error(asio::use_awaitable, error));
72 if (error == asio::error::operation_aborted || error == asio::error::bad_descriptor)
break;
74 logger::instance().log_warn(
"UDP datagram receive failed: {}", error.message());
77 const auto it = callbacks_.find(source);
78 if (it != callbacks_.end()) {
data_ptr make_shared_from(const T &t)
将任意满足 byte_container 的数据拷贝到共享缓冲。
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
auto executor()
获取全局任务上下文的executor。