Files
CPP_Core/Core/socket/UDP_Client.cpp
T
2026-07-24 10:54:45 +08:00

153 lines
5.0 KiB
C++

#include "UDP_Client.h"
#include <string_view>
namespace Psc::asio_socket {
void UDP_Client::create() {
socket = std::make_unique<asio::ip::udp::socket>(io_context);
asio::error_code ec;
socket->open(asio::ip::udp::v4(), ec);
connected = false;
connect_pending = false;
read_pending = false;
write_pending = false;
recv_storage.assign(static_cast<size_t>(read_chunk_size), 0);
send_storage.assign(static_cast<size_t>(read_chunk_size), 0);
send_buffer.init(user_buffer_size);
recv_buffer.init(user_buffer_size);
state = Not_Set_Field;
}
bool UDP_Client::connect() {
if (connected || connect_pending)
return true;
if (!socket)
create();
if (dest_address.ip.empty() || dest_address.port == 0) {
state = Not_Set_Field;
return false;
}
asio::error_code ec;
endpoint =
asio::ip::udp::endpoint(asio::ip::make_address(dest_address.ip, ec),
static_cast<unsigned short>(dest_address.port));
if (ec) {
state = Not_Set_Field;
return false;
}
io_context.restart();
connect_pending = true;
state = Connecting;
socket->async_connect(endpoint, [this](const asio::error_code& connect_ec) {
connect_pending = false;
if (connect_ec == asio::error::operation_aborted)
return;
if (connect_ec) {
connected = false;
state = Not_Set_Field;
return;
}
connected = true;
state = Working;
start_read();
start_write();
});
return true;
}
std::string UDP_Client::read() {
std::string ret(static_cast<size_t>(read_chunk_size), '\0');
std::size_t out_len = ret.size();
if (!recv_buffer.read(ret.data(), out_len))
return {};
ret.resize(out_len);
return ret;
}
void UDP_Client::tick() {
if (!connected && !connect_pending && !dest_address.ip.empty() &&
dest_address.port != 0) {
connect();
}
if (connected) {
start_read();
start_write();
}
io_context.restart();
io_context.poll();
if (connected) {
start_read();
start_write();
}
}
void UDP_Client::send(std::string_view data) {
if (data.empty())
return;
send_buffer.write(data.data(), data.size());
if (!connected)
connect();
if (connected)
start_write();
}
void UDP_Client::start_read() {
if (read_pending || !connected || !socket || !socket->is_open())
return;
if (recv_storage.empty())
recv_storage.assign(static_cast<size_t>(read_chunk_size), 0);
read_pending = true;
socket->async_receive(asio::buffer(recv_storage.data(), recv_storage.size()),
[this](const asio::error_code& ec, std::size_t n) {
read_pending = false;
if (!connected)
return;
if (ec == asio::error::operation_aborted)
return;
if (ec) {
connected = false;
state = Not_Set_Field;
return;
}
recv_buffer.write(recv_storage.data(), n);
start_read();
});
}
void UDP_Client::start_write() {
if (write_pending || !connected || !socket || !socket->is_open())
return;
if (send_storage.empty())
send_storage.assign(static_cast<size_t>(read_chunk_size), 0);
std::size_t out_len = send_storage.size();
if (!send_buffer.peek(send_storage.data(), out_len))
return;
send_storage.resize(out_len);
write_pending = true;
socket->async_send(asio::buffer(send_storage.data(), send_storage.size()),
[this](const asio::error_code& ec, std::size_t) {
write_pending = false;
if (!connected)
return;
if (ec == asio::error::operation_aborted)
return;
if (ec) {
connected = false;
state = Not_Set_Field;
return;
}
send_buffer.skip_one();
send_storage.assign(static_cast<size_t>(read_chunk_size),
0);
start_write();
});
}
void UDP_Client::close() {
connected = false;
connect_pending = false;
read_pending = false;
write_pending = false;
if (socket) {
asio::error_code ec;
socket->cancel(ec);
socket->close(ec);
}
state = Not_Created;
}
std::string UDP_Client::to_string() {
return "UDP_Client:[" + dest_address.to_string() + "]";
}
} // namespace Psc::asio_socket