1#ifndef MSTL_NETWORK_SOCKET_HPP__
2#define MSTL_NETWORK_SOCKET_HPP__
4#ifdef MSTL_PLATFORM_WINDOWS__
7#include "MSTL/core/config/undef_cmacro.hpp"
8#elif defined(MSTL_PLATFORM_LINUX__)
10#include <netinet/in.h>
18 IPV4 = AF_INET, IPV6 = AF_INET6,
20#ifdef MSTL_PLATFORM_LINUX__
22 NETLINK = AF_NETLINK, BLUETOOTH = AF_BLUETOOTH
27 STREAM = SOCK_STREAM, DATAGRAM = SOCK_DGRAM,
28 RAW = SOCK_RAW, SEQPACKET = SOCK_SEQPACKET
31enum class SOCKET_PROTOCOL :
uint16_t {
32 TCP = IPPROTO_TCP, UDP = IPPROTO_UDP,
33 IPV4 = IPPROTO_IP, IPV6 = IPPROTO_IPV6,
34 ICMP = IPPROTO_ICMP, ICMP6 = IPPROTO_ICMPV6,
35 SCTP = IPPROTO_SCTP, AUTO = 0
39#ifdef MSTL_PLATFORM_WINDOWS__
40bool MSTL_API winsock_initialized();
46#ifdef MSTL_PLATFORM_WINDOWS__
47 using socket_t = ::SOCKET;
48 static constexpr socket_t INVALID_MARK = INVALID_SOCKET;
49#elif MSTL_PLATFORM_LINUX__
51 static constexpr socket_t INVALID_MARK = -1;
55 socket_t sockfd_ = INVALID_MARK;
58 tcp_socket() noexcept = default;
59 explicit tcp_socket(const socket_t fd) : sockfd_(fd) {}
61 explicit tcp_socket(
const SOCKET_DOMAIN domain,
62 const SOCKET_TYPE type = SOCKET_TYPE::STREAM,
63 const SOCKET_PROTOCOL protocol = SOCKET_PROTOCOL::AUTO)
noexcept {
64 this->open(domain, type, protocol);
67 tcp_socket(
const tcp_socket&) =
delete;
68 tcp_socket& operator =(
const tcp_socket&) =
delete;
70 tcp_socket(tcp_socket&& other) noexcept : sockfd_(other.sockfd_) {
71 other.sockfd_ = INVALID_MARK;
73 tcp_socket& operator =(tcp_socket&& other)
noexcept {
76 sockfd_ = other.sockfd_;
77 other.sockfd_ = INVALID_MARK;
86 MSTL_NODISCARD
const tcp_socket& socket() const noexcept {
return *
this; }
87 MSTL_NODISCARD tcp_socket& socket() noexcept {
return *
this; }
88 MSTL_NODISCARD socket_t sockfd() const noexcept {
return sockfd_; }
89 MSTL_NODISCARD
bool is_valid() const noexcept {
return sockfd_ != INVALID_MARK; }
91 MSTL_NODISCARD
bool ssl_valid() const noexcept {
return false; }
92 MSTL_NODISCARD
bool tcp_valid() const noexcept {
return sockfd_ != INVALID_MARK; }
94 bool open(
const SOCKET_DOMAIN domain,
const SOCKET_TYPE type = SOCKET_TYPE::STREAM,
95 const SOCKET_PROTOCOL protocol = SOCKET_PROTOCOL::AUTO)
noexcept {
104 void close() noexcept {
105 if (sockfd_ != INVALID_MARK) {
106#ifdef MSTL_PLATFORM_WINDOWS__
107 ::closesocket(sockfd_);
108#elif defined(MSTL_PLATFORM_LINUX__)
111 sockfd_ = INVALID_MARK;
115 MSTL_NODISCARD tcp_socket accept() const noexcept {
116 ::sockaddr_in client_addr{};
117 ::socklen_t client_len =
sizeof(client_addr);
118 return tcp_socket{::accept(
120 reinterpret_cast<::sockaddr *
>(&client_addr),
124 MSTL_NODISCARD
bool listen(
const int backlog)
const noexcept {
125 return ::listen(sockfd_, backlog) == 0;
128 MSTL_NODISCARD
bool bind(::sockaddr_in& addr)
const noexcept {
129 return ::bind(sockfd_,
reinterpret_cast<::sockaddr*
>(&addr),
sizeof(addr)) == 0;
132 MSTL_NODISCARD
bool bind(
const uint16_t port)
const noexcept {
133 ::sockaddr_in addr{};
134 addr.sin_family = AF_INET;
135 addr.sin_addr.s_addr = INADDR_ANY;
136 addr.sin_port = ::htons(port);
137 return ::bind(sockfd_,
reinterpret_cast<::sockaddr*
>(&addr),
sizeof(addr)) == 0;
140 MSTL_NODISCARD
bool reuse_addr() const noexcept {
141 constexpr int opt = 1;
142 return ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,
143 reinterpret_cast<const char*
>(&opt),
sizeof(opt)) == 0;
147#ifdef MSTL_PLATFORM_WINDOWS__
148 ::DWORD tv =
static_cast<::DWORD
>(
timeout.count());
149 return ::setsockopt(sockfd_, SOL_SOCKET, SO_RCVTIMEO,
150 reinterpret_cast<const char*
>(&tv),
sizeof(tv)) == 0;
153 tv.tv_sec =
timeout.count() / 1000;
154 tv.tv_usec = (
timeout.count() % 1000) * 1000;
155 return ::setsockopt(sockfd_, SOL_SOCKET, SO_RCVTIMEO,
156 reinterpret_cast<const char*
>(&tv),
sizeof(tv)) == 0;
161#ifdef MSTL_PLATFORM_WINDOWS__
162 ::DWORD tv =
static_cast<::DWORD
>(
timeout.count());
163 return ::setsockopt(sockfd_, SOL_SOCKET, SO_SNDTIMEO,
164 reinterpret_cast<const char*
>(&tv),
sizeof(tv)) == 0;
167 tv.tv_sec =
timeout.count() / 1000;
168 tv.tv_usec = (
timeout.count() % 1000) * 1000;
169 return ::setsockopt(sockfd_, SOL_SOCKET, SO_SNDTIMEO,
170 reinterpret_cast<const char*
>(&tv),
sizeof(tv)) == 0;
174 MSTL_NODISCARD
bool connect(const ::sockaddr* addr, const ::socklen_t addr_len)
const noexcept {
175 return ::connect(sockfd_, addr, addr_len) == 0;
178 MSTL_NODISCARD
bool connect(const ::sockaddr_in& addr)
const noexcept {
179 return ::connect(sockfd_,
reinterpret_cast<const ::sockaddr*
>(&addr),
sizeof(addr)) == 0;
182 MSTL_NODISCARD
bool connect_ipv4(
const char* ip,
const uint16_t port)
const noexcept {
183 ::sockaddr_storage addr{};
184 auto *a4 =
reinterpret_cast<::sockaddr_in*
>(&addr);
185 a4->sin_family = AF_INET;
186 if (::inet_pton(AF_INET, ip, &a4->sin_addr) != 1) {
189 a4->sin_port = ::htons(port);
190 constexpr ::socklen_t addr_len =
sizeof(::sockaddr_in);
191 return ::connect(sockfd_,
reinterpret_cast<::sockaddr*
>(&addr), addr_len) == 0;
194 MSTL_NODISCARD
bool connect_ipv6(
const char* ip,
const uint16_t port)
const noexcept {
195 ::sockaddr_storage addr{};
196 auto *a6 =
reinterpret_cast<::sockaddr_in6 *
>(&addr);
197 a6->sin6_family = AF_INET6;
198 if (::inet_pton(AF_INET6, ip, &a6->sin6_addr) != 1) {
201 a6->sin6_port = ::htons(port);
202 constexpr ::socklen_t addr_len =
sizeof(::sockaddr_in6);
203 return ::connect(sockfd_,
reinterpret_cast<::sockaddr*
>(&addr), addr_len) == 0;
206 MSTL_NODISCARD
bool shutdown_send() const noexcept {
207#ifdef MSTL_PLATFORM_WINDOWS__
208 return ::shutdown(sockfd_, SD_SEND) == 0;
210 return ::shutdown(sockfd_, SHUT_WR) == 0;
214 MSTL_NODISCARD
bool shutdown_receive() const noexcept {
215#ifdef MSTL_PLATFORM_WINDOWS__
216 return ::shutdown(sockfd_, SD_RECEIVE) == 0;
218 return ::shutdown(sockfd_, SHUT_RD) == 0;
222 MSTL_NODISCARD
bool shutdown_both() const noexcept {
223#ifdef MSTL_PLATFORM_WINDOWS__
224 return ::shutdown(sockfd_, SD_BOTH) == 0;
226 return ::shutdown(sockfd_, SHUT_RDWR) == 0;
230 MSTL_NODISCARD
bool set_nonblocking(
bool nonblocking)
const noexcept {
231#ifdef MSTL_PLATFORM_WINDOWS__
232 u_long mode = nonblocking ? 1 : 0;
233 return ::ioctlsocket(sockfd_, FIONBIO, &mode) == 0;
235 int flags = ::fcntl(sockfd_, F_GETFL, 0);
242 flags &= ~O_NONBLOCK;
244 return ::fcntl(sockfd_, F_SETFL, flags) == 0;
248 MSTL_NODISCARD
ssize_t send(
const void* buf,
const size_t len,
const int flags = 0) const noexcept {
249 return ::send(sockfd_,
static_cast<const char*
>(buf), len, flags);
252 MSTL_NODISCARD
ssize_t receive(
void* buf,
const size_t len,
const int flags = 0) const noexcept {
253 return ::recv(sockfd_,
static_cast<char*
>(buf), len, flags);
256 MSTL_NODISCARD
ssize_t sendto(
const void* buf,
const size_t len, const ::sockaddr* dest_addr,
257 const ::socklen_t addrlen,
const int flags = 0) const noexcept {
258 return ::sendto(sockfd_,
static_cast<const char*
>(buf), len, flags, dest_addr, addrlen);
261 MSTL_NODISCARD
ssize_t sendto(
const void* buf,
const size_t len,
262 const ::sockaddr_in& dest_addr,
const int flags = 0) const noexcept {
264 sockfd_,
static_cast<const char*
>(buf), len, flags,
265 reinterpret_cast<const ::sockaddr*
>(&dest_addr),
sizeof(dest_addr));
268 MSTL_NODISCARD
ssize_t sendto(
const void* buf,
const size_t len,
269 const char* ip,
const uint16_t port,
const int flags = 0) const noexcept {
270 ::sockaddr_in addr{};
271 addr.sin_family = AF_INET;
272 addr.sin_port = ::htons(port);
273 if (::inet_pton(AF_INET, ip, &addr.sin_addr) != 1) {
277 sockfd_,
static_cast<const char*
>(buf), len, flags,
278 reinterpret_cast<const ::sockaddr*
>(&addr),
sizeof(addr));
281 MSTL_NODISCARD
ssize_t receive_from(
void* buf,
const size_t len, ::sockaddr* src_addr,
282 ::socklen_t* addrlen,
const int flags = 0) const noexcept {
283 return ::recvfrom(sockfd_,
static_cast<char*
>(buf), len, flags, src_addr, addrlen);
286 MSTL_NODISCARD
ssize_t receive_from(
void* buf,
const size_t len,
const int flags = 0) const noexcept {
287 ::sockaddr_in from_addr{};
288 ::socklen_t from_len =
sizeof(from_addr);
289 return ::recvfrom(sockfd_,
static_cast<char*
>(buf), len, flags,
reinterpret_cast<sockaddr*
>(&from_addr), &from_len);
293#ifdef MSTL_PLATFORM_WINDOWS__
296 FD_SET(sockfd_, &readfds);
299 tv.tv_sec =
timeout.count() / 1000;
300 tv.tv_usec = (
timeout.count() % 1000) * 1000;
302 const int result = ::select(
static_cast<int>(sockfd_) + 1, &readfds,
nullptr,
nullptr,
303 timeout.count() >= 0 ? &tv :
nullptr);
304 return result > 0 && FD_ISSET(sockfd_, &readfds);
305#elif defined(MSTL_PLATFORM_LINUX__)
308 FD_SET(sockfd_, &readfds);
311 tv.tv_sec =
timeout.count() / 1000;
312 tv.tv_usec = (
timeout.count() % 1000) * 1000;
314 const int result = ::select(sockfd_ + 1, &readfds,
nullptr,
nullptr,
315 timeout.count() >= 0 ? &tv :
nullptr);
316 return result > 0 && FD_ISSET(sockfd_, &readfds);
320 MSTL_NODISCARD
static bool is_ipv4(
const char* host)
noexcept {
322 return ::inet_pton(AF_INET, host, &(a4.sin_addr)) == 1;
325 MSTL_NODISCARD
static bool is_ipv6(
const char* host)
noexcept {
327 return ::inet_pton(AF_INET6, host, &(a6.sin6_addr)) == 1;
330 MSTL_NODISCARD
bool operator ==(
const tcp_socket& other)
const noexcept {
331 return sockfd_ == other.sockfd_;
333 MSTL_NODISCARD
bool operator !=(
const tcp_socket& other)
const noexcept {
334 return sockfd_ != other.sockfd_;
unsigned short uint16_t
16位无符号整数类型
duration< int64_t, milli > milliseconds
毫秒持续时间
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL