C++ Socket 简单封装
以下代码一部分来自于《网络多人游戏架构与编程》,
其它的都是我瞎写的。
备忘。
一个简单的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 简单封装的更多相关文章
- C# .NET Socket 简单实用框架,socket组件封装
参考资料 https://www.cnblogs.com/coldairarrow/p/7501645.html 根据.NET Socket 简单实用框架进行了改造,这个代码对socket通信封装还是 ...
- MongoDB Python官方驱动 PyMongo 的简单封装
最近,需要使用 Python 对 MongodB 做一些简单的操作,不想使用各种繁重的框架.出于可重用性的考虑,想对 MongoDB Python 官方驱动 PyMongo 做下简单封装,百度一如既往 ...
- .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 ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
- .NetCore简单封装基于IHttpClientFactory的HttpClient请求
IHttpClientFactory是什么?为什么出现了IHttpClientFactory 一.IHttpClientFactory是什么? IHttpClientFactory是.netcore2 ...
- Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...
- FMDB简单封装和使用
工具:火狐浏览器+SQLite Manager插件 ; Xcode; FMDB库; 效果: 项目地址: https://github.com/sven713/PackFMDB 主要参考这两篇博客: 1 ...
- Android--Retrofit+RxJava的简单封装(三)
1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下 先创建一个HttpMethods类,将Ret ...
- okhttp3 get post 简单封装
最近打算在新项目中使用 okhttp3, 简单封装了一下异步 get post 因为 CallBack 也是在子线程中执行,所以用到了 Handler public class MyOkHttpCli ...
随机推荐
- C语言之三字棋的简单实现及扩展
C语言之三字棋的简单实现及扩展 在我们学习完数组之后,我们完全可以利用数组相关知识来写一个微小型的游戏,比如说今天所说的--三子棋. 大纲: 文件组成 实现 完整代码展示 扩展 即: 一.文件 ...
- 给出镜像FreeBSD 基本要求
硬盘 ports 500G update 500G portsnap 500G pkg arm64 amd64 i386 11-12-13 4TB 网络流量一个月专线大概2w RMB CPU 内存 其 ...
- Everything is Serverless,从开源框架对比说起
摘要:Everything is Serverless. 在众多云计算解决方案中,Serverless 逐渐崭露头角,受到了很多关注并且发展迅猛,今天就关于serverless 开源框架细说二三. 什 ...
- C# 应用 - 使用 WebClient 发起 Http 请求
1. 需要的库类 \Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll System.Net.WebCli ...
- Mybatis最权威的知识点
1.什么是Mybatis? (1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动.创建连接.创建statement ...
- 用 Numba 加速 Python 代码
原文出自微信公众号:Python那些事 一.介绍 pip install numba Numba 是 python 的即时(Just-in-time)编译器,即当你调用 python 函数时,你的全部 ...
- js_笔记_8月7日记录_活动对象_作用域链_按值传递
活动对象:简单说就是这个函数的参数和显示声明的变量或函数. 函数内接受的参数实际是创建了一个局部变量:[形参名] = [传进来的值],js的函数传参只传值. 作用域链:执行流进入一个函数,会先创建出作 ...
- 【JVM进阶之路】一:Java虚拟机概览
1.Java简史 Java语言是一门通用的.面向对象的.支持并发的程序语言.全球从事Java相关开发的人员已经数以百万计. 从1995年"Java"正式出现以来,Java已经经历了 ...
- c++ 反汇编 局部静态变量
vs2017下测试 34: for (int i = 0; i < 5; i++) 0029734E C7 45 F8 00 00 00 00 mov dword ptr [ebp-8],0 0 ...
- Windows下C++/Fortran调用.exe可执行文件
目录 软件环境 Windows下CMake编译配置 设置项目的generator Command Line CMake GUI PreLoad.cmake 设置make 示例程序 CMake 设置Fo ...