GKD.RoboCtrl
RoboMaster Linux 电控:异步 IO、设备驱动与机器人控制
载入中...
搜索中...
未找到
udp_server.cpp
1#include "io/udp_server.hpp"
2
3#include <stdexcept>
4
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");
8 // Validate the address without opening a socket in the construct phase.
9 asio::ip::make_address(info_.address);
10}
11
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());
16 socket_.bind(local);
17 connected_ = true;
18}
19
20void udp_server::start() {
21 if (started_) return;
22 if (!connected_) throw std::logic_error("UDP server start before connect");
23 started_ = true;
24 roboctrl::spawn(task());
25}
26
27void udp_server::stop() {
28 asio::error_code ignored;
29 socket_.close(ignored);
30 started_ = false;
31 connected_ = false;
32}
33
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");
38 }
39 if (queued_bytes_ + data.size() > 65536) {
40 logger::instance().log_warn("drop UDP datagram: transmit queue full");
41 co_return;
42 }
43 queue_.push_back({peer, {data.begin(), data.end()}});
44 queued_bytes_ += data.size();
45 if (!sending_) {
46 sending_ = true;
47 roboctrl::spawn(send_task());
48 }
49}
50
51awaitable<void> udp_server::send_task() {
52 while (!queue_.empty()) {
53 auto packet = std::move(queue_.front());
54 queue_.pop_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());
61 }
62 }
63 sending_ = false;
64}
65
66awaitable<void> udp_server::task() {
67 while (started_) {
68 endpoint source;
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;
73 if (error) {
74 logger::instance().log_warn("UDP datagram receive failed: {}", error.message());
75 continue;
76 }
77 const auto it = callbacks_.find(source);
78 if (it != callbacks_.end()) {
79 it->second(make_shared_from(byte_span{buffer_.data(), size}));
80 }
81 }
82}
83
84} // namespace roboctrl::io
data_ptr make_shared_from(const T &t)
将任意满足 byte_container 的数据拷贝到共享缓冲。
Definition base.hpp:94
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
Definition async.hpp:191
auto executor()
获取全局任务上下文的executor。
Definition async.hpp:271