MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
tcp_socket.hpp
1#ifndef MSTL_NETWORK_SOCKET_HPP__
2#define MSTL_NETWORK_SOCKET_HPP__
4#ifdef MSTL_PLATFORM_WINDOWS__
5#include <WinSock2.h>
6#include <ws2tcpip.h>
7#include "MSTL/core/config/undef_cmacro.hpp"
8#elif defined(MSTL_PLATFORM_LINUX__)
9#include <sys/socket.h>
10#include <netinet/in.h>
11#include <arpa/inet.h>
12#include <fcntl.h>
13#include <unistd.h>
14#endif
16
17enum class SOCKET_DOMAIN : uint16_t {
18 IPV4 = AF_INET, IPV6 = AF_INET6,
19 UNIX = AF_UNIX,
20#ifdef MSTL_PLATFORM_LINUX__
21 LOCAL = AF_LOCAL,
22 NETLINK = AF_NETLINK, BLUETOOTH = AF_BLUETOOTH
23#endif
24};
25
26enum class SOCKET_TYPE : uint16_t {
27 STREAM = SOCK_STREAM, DATAGRAM = SOCK_DGRAM,
28 RAW = SOCK_RAW, SEQPACKET = SOCK_SEQPACKET
29};
30
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
36};
37
38
39#ifdef MSTL_PLATFORM_WINDOWS__
40bool MSTL_API winsock_initialized();
41#endif
42
43
44class tcp_socket {
45public:
46#ifdef MSTL_PLATFORM_WINDOWS__
47 using socket_t = ::SOCKET;
48 static constexpr socket_t INVALID_MARK = INVALID_SOCKET;
49#elif MSTL_PLATFORM_LINUX__
50 using socket_t = int;
51 static constexpr socket_t INVALID_MARK = -1;
52#endif
53
54private:
55 socket_t sockfd_ = INVALID_MARK;
56
57public:
58 tcp_socket() noexcept = default;
59 explicit tcp_socket(const socket_t fd) : sockfd_(fd) {}
60
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);
65 }
66
67 tcp_socket(const tcp_socket&) = delete;
68 tcp_socket& operator =(const tcp_socket&) = delete;
69
70 tcp_socket(tcp_socket&& other) noexcept : sockfd_(other.sockfd_) {
71 other.sockfd_ = INVALID_MARK;
72 }
73 tcp_socket& operator =(tcp_socket&& other) noexcept {
74 if (this != &other) {
75 close();
76 sockfd_ = other.sockfd_;
77 other.sockfd_ = INVALID_MARK;
78 }
79 return *this;
80 }
81
82 ~tcp_socket() {
83 close();
84 }
85
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; }
90
91 MSTL_NODISCARD bool ssl_valid() const noexcept { return false; }
92 MSTL_NODISCARD bool tcp_valid() const noexcept { return sockfd_ != INVALID_MARK; }
93
94 bool open(const SOCKET_DOMAIN domain, const SOCKET_TYPE type = SOCKET_TYPE::STREAM,
95 const SOCKET_PROTOCOL protocol = SOCKET_PROTOCOL::AUTO) noexcept {
96 sockfd_ = ::socket(
97 static_cast<uint16_t>(domain),
98 static_cast<uint16_t>(type),
99 static_cast<uint16_t>(protocol)
100 );
101 return is_valid();
102 }
103
104 void close() noexcept {
105 if (sockfd_ != INVALID_MARK) {
106#ifdef MSTL_PLATFORM_WINDOWS__
107 ::closesocket(sockfd_);
108#elif defined(MSTL_PLATFORM_LINUX__)
109 ::close(sockfd_);
110#endif
111 sockfd_ = INVALID_MARK;
112 }
113 }
114
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(
119 sockfd_,
120 reinterpret_cast<::sockaddr *>(&client_addr),
121 &client_len)};
122 }
123
124 MSTL_NODISCARD bool listen(const int backlog) const noexcept {
125 return ::listen(sockfd_, backlog) == 0;
126 }
127
128 MSTL_NODISCARD bool bind(::sockaddr_in& addr) const noexcept {
129 return ::bind(sockfd_, reinterpret_cast<::sockaddr*>(&addr), sizeof(addr)) == 0;
130 }
131
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;
138 }
139
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;
144 }
145
146 MSTL_NODISCARD bool set_receive_timeout(const milliseconds timeout) const noexcept {
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;
151#else
152 ::timeval tv{};
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;
157#endif
158 }
159
160 MSTL_NODISCARD bool set_send_timeout(const milliseconds timeout) const noexcept {
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;
165#else
166 ::timeval tv{};
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;
171#endif
172 }
173
174 MSTL_NODISCARD bool connect(const ::sockaddr* addr, const ::socklen_t addr_len) const noexcept {
175 return ::connect(sockfd_, addr, addr_len) == 0;
176 }
177
178 MSTL_NODISCARD bool connect(const ::sockaddr_in& addr) const noexcept {
179 return ::connect(sockfd_, reinterpret_cast<const ::sockaddr*>(&addr), sizeof(addr)) == 0;
180 }
181
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) {
187 return false;
188 }
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;
192 }
193
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) {
199 return false;
200 }
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;
204 }
205
206 MSTL_NODISCARD bool shutdown_send() const noexcept {
207#ifdef MSTL_PLATFORM_WINDOWS__
208 return ::shutdown(sockfd_, SD_SEND) == 0;
209#else
210 return ::shutdown(sockfd_, SHUT_WR) == 0;
211#endif
212 }
213
214 MSTL_NODISCARD bool shutdown_receive() const noexcept {
215#ifdef MSTL_PLATFORM_WINDOWS__
216 return ::shutdown(sockfd_, SD_RECEIVE) == 0;
217#else
218 return ::shutdown(sockfd_, SHUT_RD) == 0;
219#endif
220 }
221
222 MSTL_NODISCARD bool shutdown_both() const noexcept {
223#ifdef MSTL_PLATFORM_WINDOWS__
224 return ::shutdown(sockfd_, SD_BOTH) == 0;
225#else
226 return ::shutdown(sockfd_, SHUT_RDWR) == 0;
227#endif
228 }
229
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;
234#else
235 int flags = ::fcntl(sockfd_, F_GETFL, 0);
236 if (flags == -1) {
237 return false;
238 }
239 if (nonblocking) {
240 flags |= O_NONBLOCK;
241 } else {
242 flags &= ~O_NONBLOCK;
243 }
244 return ::fcntl(sockfd_, F_SETFL, flags) == 0;
245#endif
246 }
247
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);
250 }
251
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);
254 }
255
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);
259 }
260
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 {
263 return ::sendto(
264 sockfd_, static_cast<const char*>(buf), len, flags,
265 reinterpret_cast<const ::sockaddr*>(&dest_addr), sizeof(dest_addr));
266 }
267
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) {
274 return -1;
275 }
276 return ::sendto(
277 sockfd_, static_cast<const char*>(buf), len, flags,
278 reinterpret_cast<const ::sockaddr*>(&addr), sizeof(addr));
279 }
280
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);
284 }
285
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);
290 }
291
292 MSTL_NODISCARD bool has_data_available(const milliseconds timeout = milliseconds(0)) const noexcept {
293#ifdef MSTL_PLATFORM_WINDOWS__
294 fd_set readfds;
295 FD_ZERO(&readfds);
296 FD_SET(sockfd_, &readfds);
297
298 ::timeval tv;
299 tv.tv_sec = timeout.count() / 1000;
300 tv.tv_usec = (timeout.count() % 1000) * 1000;
301
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__)
306 ::fd_set readfds{};
307 FD_ZERO(&readfds);
308 FD_SET(sockfd_, &readfds);
309
310 ::timeval tv{};
311 tv.tv_sec = timeout.count() / 1000;
312 tv.tv_usec = (timeout.count() % 1000) * 1000;
313
314 const int result = ::select(sockfd_ + 1, &readfds, nullptr, nullptr,
315 timeout.count() >= 0 ? &tv : nullptr);
316 return result > 0 && FD_ISSET(sockfd_, &readfds);
317#endif
318 }
319
320 MSTL_NODISCARD static bool is_ipv4(const char* host) noexcept {
321 ::sockaddr_in a4{};
322 return ::inet_pton(AF_INET, host, &(a4.sin_addr)) == 1;
323 }
324
325 MSTL_NODISCARD static bool is_ipv6(const char* host) noexcept {
326 ::sockaddr_in6 a6{};
327 return ::inet_pton(AF_INET6, host, &(a6.sin6_addr)) == 1;
328 }
329
330 MSTL_NODISCARD bool operator ==(const tcp_socket& other) const noexcept {
331 return sockfd_ == other.sockfd_;
332 }
333 MSTL_NODISCARD bool operator !=(const tcp_socket& other) const noexcept {
334 return sockfd_ != other.sockfd_;
335 }
336};
337
339#endif // MSTL_NETWORK_SOCKET_HPP__
MSTL持续时间类型
unsigned short uint16_t
16位无符号整数类型
duration< int64_t, milli > milliseconds
毫秒持续时间
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
int64_t ssize_t
有符号大小类型