add udp client

pull/1745/head
boddykong 5 years ago
parent c2ed51a733
commit e2217b0e3c

@ -21,13 +21,14 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class tcp_client class udp_client
{ {
SOCKET socket_ = INVALID_SOCKET; SOCKET socket_ = INVALID_SOCKET;
sockaddr_in addr_ = { 0 };
static bool winsock_initialized_() static bool winsock_initialized_()
{ {
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKET s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) if (s == INVALID_SOCKET)
{ {
return false; return false;
@ -59,30 +60,12 @@ class tcp_client
} }
public: public:
bool is_connected() const bool is_init() const
{ {
return socket_ != INVALID_SOCKET; return socket_ != INVALID_SOCKET;
} }
void close() bool init(const std::string &host, int port)
{
::closesocket(socket_);
socket_ = INVALID_SOCKET;
WSACleanup();
}
SOCKET fd() const
{
return socket_;
}
~tcp_client()
{
close();
}
// try to connect or throw on failure
void connect(const std::string &host, int port)
{ {
// initialize winsock if needed // initialize winsock if needed
if (!winsock_initialized_()) if (!winsock_initialized_())
@ -90,84 +73,42 @@ public:
init_winsock_(); init_winsock_();
} }
if (is_connected()) if (is_init())
{ {
close(); close();
} }
struct addrinfo hints
{};
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
hints.ai_protocol = 0;
auto port_str = std::to_string(port);
struct addrinfo *addrinfo_result;
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
int last_error = 0;
if (rv != 0)
{
last_error = ::WSAGetLastError();
WSACleanup();
throw_winsock_error_("getaddrinfo failed", last_error);
}
// Try each address until we successfully connect(2). addr_.sin_family = AF_INET;
addr_.sin_port = htons(port);
addr_.sin_addr.S_un.S_addr = inet_addr(host.c_str());
return true;
}
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) void close()
{
socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (socket_ == INVALID_SOCKET)
{ {
last_error = ::WSAGetLastError(); ::closesocket(socket_);
socket_ = INVALID_SOCKET;
WSACleanup(); WSACleanup();
continue;
} }
if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0)
SOCKET fd() const
{ {
break; return socket_;
} }
else
~udp_client()
{ {
last_error = ::WSAGetLastError();
close(); close();
} }
}
::freeaddrinfo(addrinfo_result);
if (socket_ == INVALID_SOCKET)
{
WSACleanup();
throw_winsock_error_("connect failed", last_error);
}
// set TCP_NODELAY
int enable_flag = 1;
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char *)&enable_flag, sizeof(enable_flag));
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void send(const char *data, size_t n_bytes) void send(const char *data, size_t n_bytes)
{ {
size_t bytes_sent = 0; size_t toslen = 0;
while (bytes_sent < n_bytes) size_t tolen = sizeof(struct sockaddr);
if (( toslen = sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&addr_, tolen)) == -1)
{ {
const int send_flags = 0; throw_spdlog_ex("write(2) failed", errno);
auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags);
if (write_result == SOCKET_ERROR)
{
int last_error = ::WSAGetLastError();
close(); close();
throw_winsock_error_("send failed", last_error);
}
if (write_result == 0) // (probably should not happen but in any case..)
{
break;
}
bytes_sent += static_cast<size_t>(write_result);
} }
} }
}; };

@ -24,16 +24,11 @@ namespace details {
class udp_client class udp_client
{ {
int socket_ = -1; int socket_ = -1;
std::string m_svrIp;
int m_svrPort;
struct sockaddr_in sockAddr_; struct sockaddr_in sockAddr_;
public: public:
bool init(const std::string &host, int port) bool init(const std::string &host, int port)
{ {
m_svrIp = host;
m_svrPort = port;
socket_ = socket(PF_INET, SOCK_DGRAM, 0); socket_ = socket(PF_INET, SOCK_DGRAM, 0);
if (socket_ < 0) if (socket_ < 0)
{ {
@ -42,8 +37,8 @@ public:
} }
sockAddr_.sin_family = AF_INET; sockAddr_.sin_family = AF_INET;
sockAddr_.sin_port = htons(m_svrPort); sockAddr_.sin_port = htons(port);
inet_aton(m_svrIp.c_str(), &sockAddr_.sin_addr); inet_aton(host.c_str(), &sockAddr_.sin_addr);
memset(sockAddr_.sin_zero, 0x00, 8); memset(sockAddr_.sin_zero, 0x00, 8);
return true; return true;
@ -82,6 +77,7 @@ public:
if (( toslen = sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) if (( toslen = sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1)
{ {
throw_spdlog_ex("write(2) failed", errno); throw_spdlog_ex("write(2) failed", errno);
close();
} }
} }
}; };

@ -7,7 +7,7 @@
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#ifdef _WIN32 #ifdef _WIN32
#include <spdlog/details/tcp_client-windows.h> #include <spdlog/details/udp_client-windows.h>
#else #else
#include <spdlog/details/udp_client.h> #include <spdlog/details/udp_client.h>
#endif #endif

Loading…
Cancel
Save