150 lines
3.5 KiB
C++
150 lines
3.5 KiB
C++
// UDP_Server.cpp
|
|
#include "UDP_Server.h"
|
|
#include <algorithm>
|
|
|
|
namespace Psc::socket {
|
|
|
|
static bool same_endpoint(const Sockaddr_In& a, const Sockaddr_In& b) {
|
|
return a.ip == b.ip && a.port == b.port;
|
|
}
|
|
|
|
void UDP_Server::create() {
|
|
|
|
bound = false;
|
|
has_last_peer = false;
|
|
clients.clear();
|
|
|
|
auto rsf = socket::create_socket_fd(Socket_Type::UDP);
|
|
if (!rsf) {
|
|
return;
|
|
}
|
|
socket_fd = rsf.value();
|
|
state = Not_Set_Field;
|
|
// 只能非阻塞
|
|
auto r2 = socket::set_block(socket_fd, false)
|
|
.and_then([this]() { return socket::set_reuse_addr(socket_fd, true); })
|
|
.and_then([this]() { return socket::set_debug(socket_fd, true); })
|
|
.and_then([this]() { return socket::set_buffer_size(socket_fd, buffer_size); });
|
|
|
|
if (!r2) {
|
|
state = Not_Bind;
|
|
}
|
|
socket_fd = rsf.value();
|
|
}
|
|
|
|
bool UDP_Server::bind() {
|
|
if (socket_fd == -1) {
|
|
create();
|
|
if (socket_fd == -1) return false;
|
|
}
|
|
auto r = socket::bind(socket_fd, bind_address);
|
|
if (!r) {
|
|
bound = false;
|
|
return false;
|
|
}
|
|
state = Working;
|
|
bound = true;
|
|
return true;
|
|
}
|
|
|
|
// std::string UDP_Server::read() {
|
|
// if (!bound) {
|
|
// if (!bind()) return {};
|
|
// }
|
|
//
|
|
// Sockaddr_In peer{};
|
|
// auto r = socket::UDP::recvfrom(socket_fd, &peer, read_chunk_size);
|
|
// if (!r) {
|
|
// return {};
|
|
// }
|
|
//
|
|
// last_peer = peer;
|
|
// has_last_peer = true;
|
|
//
|
|
// // 收集 client:去重加入
|
|
// const bool exists =
|
|
// std::any_of(clients.begin(), clients.end(),
|
|
// [&](const Sockaddr_In& c) { return same_endpoint(c, peer); });
|
|
// if (!exists) {
|
|
// clients.push_back(peer);
|
|
// }
|
|
//
|
|
// return r.value();
|
|
// }
|
|
|
|
void UDP_Server::tick() {
|
|
if (!bound) {
|
|
if (!bind()) return;
|
|
}
|
|
|
|
Sockaddr_In peer{};
|
|
auto r = socket::UDP::recvfrom(socket_fd, &peer, read_chunk_size);
|
|
if (!r) return;
|
|
if (peer.ip == "" && peer.port == 0) return; // 不知道为什么会有这个
|
|
|
|
|
|
last_peer = peer;
|
|
has_last_peer = true;
|
|
|
|
// 连接/断开切换:存在 => 断开(移除),不存在 => 连接(加入)
|
|
auto it = std::find_if(clients.begin(), clients.end(),
|
|
[&](const Sockaddr_In& c) { return same_endpoint(c, peer); });
|
|
|
|
if (it == clients.end()) {
|
|
// 第一次:连接
|
|
clients.push_back(peer);
|
|
// 可选:你可以在这里记录事件类型
|
|
// last_event = PeerConnected;
|
|
} else {
|
|
// 第二次:断开
|
|
clients.erase(it);
|
|
// last_event = PeerDisconnected;
|
|
}
|
|
|
|
// 如果“第一次/第二次包”只是控制含义,直接不向上层返回数据:
|
|
return;
|
|
|
|
// 如果你仍想把该包内容交给上层处理,改成:
|
|
// return r.value();
|
|
}
|
|
|
|
void UDP_Server::close() {
|
|
if (socket_fd != -1) {
|
|
(void)socket::close(socket_fd);
|
|
socket_fd = -1;
|
|
state = Not_Created;
|
|
}
|
|
bound = false;
|
|
has_last_peer = false;
|
|
clients.clear();
|
|
}
|
|
|
|
void UDP_Server::reply_last_peer(const std::string& data) {
|
|
if (socket_fd == -1 || !bound || !has_last_peer) return;
|
|
(void)socket::UDP::sendto(socket_fd, last_peer.ip, last_peer.port, data);
|
|
}
|
|
|
|
void UDP_Server::send_to(const std::string& ip, uint16_t port, const std::string& data) {
|
|
if (socket_fd == -1) {
|
|
create();
|
|
if (socket_fd == -1) return;
|
|
}
|
|
if (!bound) {
|
|
if (!bind()) return;
|
|
}
|
|
(void)socket::UDP::sendto(socket_fd, ip, port, data);
|
|
}
|
|
|
|
void UDP_Server::write_to_all_clients(const std::string& msg) {
|
|
if (socket_fd == -1) return;
|
|
if (!bound) {
|
|
if (!bind()) return;
|
|
}
|
|
|
|
for (const auto& c : clients) {
|
|
(void)socket::UDP::sendto(socket_fd, c.ip, c.port, msg);
|
|
}
|
|
}
|
|
|
|
}
|