emsApplication/sdk/include/hv/UdpServer.h

175 lines
4.7 KiB
C
Raw Permalink Normal View History

2024-05-24 12:23:42 +08:00
#ifndef HV_UDP_SERVER_HPP_
#define HV_UDP_SERVER_HPP_
#include "hsocket.h"
#include "EventLoopThreadPool.h"
#include "Channel.h"
namespace hv {
template<class TSocketChannel = SocketChannel>
2024-05-24 12:29:09 +08:00
class UdpServerEventLoopTmpl {
2024-05-24 12:23:42 +08:00
public:
typedef std::shared_ptr<TSocketChannel> TSocketChannelPtr;
2024-05-24 12:29:09 +08:00
UdpServerEventLoopTmpl(EventLoopPtr loop = NULL) {
loop_ = loop ? loop : std::make_shared<EventLoop>();
port = 0;
2024-05-24 12:23:42 +08:00
#if WITH_KCP
2024-05-24 12:29:09 +08:00
kcp_setting = NULL;
2024-05-24 12:23:42 +08:00
#endif
}
2024-05-24 12:29:09 +08:00
virtual ~UdpServerEventLoopTmpl() {
#if WITH_KCP
HV_FREE(kcp_setting);
#endif
2024-05-24 12:23:42 +08:00
}
const EventLoopPtr& loop() {
2024-05-24 12:29:09 +08:00
return loop_;
2024-05-24 12:23:42 +08:00
}
//@retval >=0 bindfd, <0 error
int createsocket(int port, const char* host = "0.0.0.0") {
2024-05-24 12:29:09 +08:00
hio_t* io = hloop_create_udp_server(loop_->loop(), host, port);
2024-05-24 12:23:42 +08:00
if (io == NULL) return -1;
2024-05-24 12:29:09 +08:00
this->host = host;
this->port = port;
channel = std::make_shared<TSocketChannel>(io);
2024-05-24 12:23:42 +08:00
return channel->fd();
}
// closesocket thread-safe
void closesocket() {
if (channel) {
channel->close(true);
}
}
int startRecv() {
2024-05-24 12:29:09 +08:00
if (channel == NULL || channel->isClosed()) {
int bindfd = createsocket(port, host.c_str());
if (bindfd < 0) {
hloge("createsocket %s:%d return %d!\n", host.c_str(), port, bindfd);
return bindfd;
}
}
if (channel == NULL || channel->isClosed()) {
return -1;
}
2024-05-24 12:23:42 +08:00
channel->onread = [this](Buffer* buf) {
if (onMessage) {
onMessage(channel, buf);
}
};
channel->onwrite = [this](Buffer* buf) {
if (onWriteComplete) {
onWriteComplete(channel, buf);
}
};
#if WITH_KCP
2024-05-24 12:29:09 +08:00
if (kcp_setting) {
hio_set_kcp(channel->io(), kcp_setting);
2024-05-24 12:23:42 +08:00
}
#endif
return channel->startRead();
}
2024-05-24 12:29:09 +08:00
int stopRecv() {
if (channel == NULL) return -1;
return channel->stopRead();
2024-05-24 12:23:42 +08:00
}
2024-05-24 12:29:09 +08:00
// start thread-safe
void start() {
loop_->runInLoop(std::bind(&UdpServerEventLoopTmpl::startRecv, this));
2024-05-24 12:23:42 +08:00
}
// sendto thread-safe
int sendto(const void* data, int size, struct sockaddr* peeraddr = NULL) {
if (channel == NULL) return -1;
std::lock_guard<std::mutex> locker(sendto_mutex);
if (peeraddr) hio_set_peeraddr(channel->io(), peeraddr, SOCKADDR_LEN(peeraddr));
return channel->write(data, size);
}
int sendto(Buffer* buf, struct sockaddr* peeraddr = NULL) {
return sendto(buf->data(), buf->size(), peeraddr);
}
int sendto(const std::string& str, struct sockaddr* peeraddr = NULL) {
return sendto(str.data(), str.size(), peeraddr);
}
2024-05-24 12:29:09 +08:00
#if WITH_KCP
void setKcp(kcp_setting_t* setting) {
if (setting == NULL) {
HV_FREE(kcp_setting);
return;
}
if (kcp_setting == NULL) {
HV_ALLOC_SIZEOF(kcp_setting);
}
*kcp_setting = *setting;
}
#endif
2024-05-24 12:23:42 +08:00
public:
2024-05-24 12:29:09 +08:00
std::string host;
int port;
2024-05-24 12:23:42 +08:00
TSocketChannelPtr channel;
#if WITH_KCP
2024-05-24 12:29:09 +08:00
kcp_setting_t* kcp_setting;
2024-05-24 12:23:42 +08:00
#endif
// Callback
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
// NOTE: Use Channel::isWriteComplete in onWriteComplete callback to determine whether all data has been written.
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
private:
std::mutex sendto_mutex;
2024-05-24 12:29:09 +08:00
EventLoopPtr loop_;
};
template<class TSocketChannel = SocketChannel>
class UdpServerTmpl : private EventLoopThread, public UdpServerEventLoopTmpl<TSocketChannel> {
public:
UdpServerTmpl(EventLoopPtr loop = NULL)
: EventLoopThread(loop)
, UdpServerEventLoopTmpl<TSocketChannel>(EventLoopThread::loop())
, is_loop_owner(loop == NULL)
{}
virtual ~UdpServerTmpl() {
stop(true);
}
const EventLoopPtr& loop() {
return EventLoopThread::loop();
}
// start thread-safe
void start(bool wait_threads_started = true) {
if (isRunning()) {
UdpServerEventLoopTmpl<TSocketChannel>::start();
} else {
EventLoopThread::start(wait_threads_started, std::bind(&UdpServerTmpl::startRecv, this));
}
}
// stop thread-safe
void stop(bool wait_threads_stopped = true) {
UdpServerEventLoopTmpl<TSocketChannel>::closesocket();
if (is_loop_owner) {
EventLoopThread::stop(wait_threads_stopped);
}
}
private:
bool is_loop_owner;
2024-05-24 12:23:42 +08:00
};
typedef UdpServerTmpl<SocketChannel> UdpServer;
}
#endif // HV_UDP_SERVER_HPP_