网络资源的初始化与释放(C++ RAII惯用法)

1. 网络资源的初始化与释放(C++ RAII惯用法)

C++ RAII 惯用法

RAII (Resource Acquisition Is Initialization)资源获取即初始化

我们拿到资源的时候就已经初始化,一旦不需要该资源,该资源就会被释放

资源:

在 C++ 的语境下,资源代表一些可以必须先被获取才能使用的对象。例如堆内存是资源,文件句柄是资源,互斥锁也是资源。

千言万语,比不上一段代码:

ServerSocket.h

class CServerSocket
{
public:static CServerSocket* getInstance(){if(m_instance == nullptr){m_instance = new CServerSocket();}return  m_instance;}bool InitSocket(){if (m_sock == -1) return false;sockaddr_in serv_adr;memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.S_un.S_addr = INADDR_ANY;serv_adr.sin_port = htons(18888);//绑定if (bind(m_sock, (sockaddr*)&serv_adr, sizeof(sockaddr_in) ) == -1) return false;//TODO: 返回值if( listen(m_sock, 5) == -1) return false;return true;}bool AcceptClient(){sockaddr_in client_adr;int cli_sz = sizeof(client_adr);m_client = accept(m_sock, (sockaddr*)&client_adr, &cli_sz);if (m_client == -1) return  false;return true;}int DealCommand(){if (m_client == -1){return -1;}char* buffer = new char[4096];memset(buffer, 0, 4096);size_t index = 0;while(true){size_t len = recv(m_client, buffer +index, sizeof(buffer) - index, 0);if(len <= 0 ){return -1;}//TODO: 处理命令index += len;len = index;m_packet =  CPacket ((BYTE*)buffer, len);if(len > 0){memmove(buffer, buffer + len, 4096 - len);index -= len;return m_packet.sCmd;}}return -1;}bool Send(const char* pData,size_t nSize){if (m_client == -1) return false;return  send(m_client, pData, nSize, 0) > 0;}bool Send( CPacket& pack){if (m_client == -1) return false;return  send(m_client, pack.Data(), pack.size(), 0) > 0;}CServerSocket& operator=(const CServerSocket& ss) = delete;CServerSocket(const CServerSocket&) = delete;
private:SOCKET m_sock;SOCKET m_client;CPacket m_packet;CServerSocket():m_client(INVALID_SOCKET){	if(InitSockEnv() == FALSE){MessageBox(NULL, _T("无法初始化套接字环境,请检查网络设置"), _T("初始化错误"), MB_OK | MB_ICONERROR);exit(0);}m_sock = socket(PF_INET, SOCK_STREAM, 0);};~CServerSocket(){closesocket(m_sock);WSACleanup();};BOOL InitSockEnv(){WSADATA data;if(WSAStartup(MAKEWORD(1, 1), &data) != 0){return  FALSE;}return TRUE;//TODO: 返回值处理}static  CServerSocket* m_instance;static  void releaseInstance(){if(m_instance != NULL){CServerSocket* tmp = m_instance;m_instance  = NULL;delete tmp;}}class CHelper{public:CHelper(){CServerSocket::getInstance();}~CHelper(){CServerSocket::releaseInstance();}};static CHelper m_helper;
};

ServerSocket.cpp

CServerSocket* CServerSocket::m_instance = NULL;
CServerSocket::CHelper CServerSocket::m_helper;
CServerSocket* pserver = CServerSocket::getInstance();

main.cpp

CServerSocket* pserver =  CServerSocket::getInstance();int count = 0;if (pserver->InitSocket() == false){MessageBox(NULL, _T(""), _T("网络初始化失败"), MB_OK | MB_ICONERROR);exit(0);}while (pserver != NULL){if (pserver){if (pserver->AcceptClient() == false){if (count >= 3) {MessageBox(NULL, _T("多次无法正常接入,程序退出"), _T("接入用户失败"), MB_OK | MB_ICONERROR);exit(0);}MessageBox(NULL, _T("无法正常接入用户,自动重试"), _T("接入用户失败"), MB_OK | MB_ICONERROR);count++;}}int ret = pserver->DealCommand();

以上就是RAII的一种实现,但是又采用单例模式(下文讲解)

我们在构造函数CServerSocket()调用InitSockEnv()获取并初始化网络资源,在进入main函数后,获取实例

main()函数结束后,应该调用析构函数,但事实上调用不了,因为此时全局数据区中,存储的并不是一个实例对象,而是一个实例对象的指针,即一个地址变量而已!实例对象呢?在堆区,因为是通过new得来的!虽然这样能够减小全局数据区的占用,把实例对象这一大坨都放到堆区。

所以我你们需要一个CHelper类,来帮助我们关闭套接字,释放网络资源我们在Server.cpp文件中创建了一个CHelper的静态对象,当main()函数结束时,由于m_helper对象在全局数据区,所以会调用CHelper的析构函数,从而调用CServerSocket::releaseInstance()帮助我们释放资源

main()函数开始时获取并初始化网络资源,在main()函数结束时,释放回收网络资源,这就是RAII

因为网络资源在整个程序运行时.只需要初始化一次,释放一次,所以``CServerSocket`采用单例模式,这样就避免了重复初始化

C++11采用智能指针也可以实现单例模式,以后可能会介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美国Palmbeach大学服务器整合改造案例

位于美国佛罗里达州的palmbeach大学&#xff0c;有4万9千多在校学生和2000多名教工。据学校的信息主管t parziale介绍&#xff0c;目前学校正在进行一个投资160多万美元的关于信息中心服务器、存储、网络等3部分整合改造并简化管理的项目。 该项目主要改造内容是&#xff1a;用…

避免switch嵌套的一种方法

避免switch嵌套的一种方法 DWORD nFlags 0;switch (mouse.nButton){case 0: //左键nFlags 1;case 1: //右键nFlags 2;break;case 2: //中间nFlags 4;break;case 4:nFlags 8;break;}if (nFlags ! 8)SetCursorPos(mouse.ptXY.x, mouse.ptXY.y);switch (mouse.nAction){case…

Enterprise Library 2.0 Hands On Lab 翻译(3):数据访问程序块(三)

练习3&#xff1a;加密数据库连接信息通过该练习&#xff0c;你将学会如何去加密数据库连接信息。第一步打开DataEx3.sln项目&#xff0c;默认的安装路径应该为C:\Program Files\Microsoft Enterprise Library January 2006\labs\cs\Data Access\exercises\ex03\begin&#xff…

操作系统进程学习(Linux 内核学习笔记)

操作系统进程学习(Linux 内核学习笔记) 进程优先级 并非所有进程都具有相同的重要性。除了大多数我们所熟悉的进程优先级之外&#xff0c;进程还有不同的关键度类别&#xff0c;以满足不同需求。首先进程比较粗糙的划分&#xff0c;进程可以分为实时进程 和非实时进程&#x…

gcc对C语言的扩展:语句内嵌表达式(statement-embedded expression)

在gnu c 中&#xff0c;用括号将复合语句括起来也形成了表达式。他允许你在一个表达式内使用循环&#xff0c;跳转和局部变量。一个复合语句是用大括号{}括起来的一组语句。在包含语句的表达式这种结构中&#xff0c;再用括号( )将大括号括起来,例如&#xff1a;({ int y foo …

react学习(56)--常见HTTP错误

200: 服务器成功返回请求的数据。,201: 新建或修改数据成功。,202: 一个请求已经进入后台排队&#xff08;异步任务&#xff09;。,204: 删除数据成功。,400: 发出的请求有错误&#xff0c;服务器没有进行新建或修改数据的操作。,401: 用户没有权限&#xff08;令牌、用户名、密…

C#二叉树递归实现

二叉树类(binaryTree.cs) using System; namespace binary_tree_demo { class BinaryTreeNode where T : IComparable { public BinaryTreeNode() { left null; right null; } public BinaryTreeNode(BinaryTreeNode l, BinaryTreeNode r) { left l; right r; } public Bin…

Linux守护进程的创建(结合nginx框架)

Linux守护进程的创建(结合nginx框架) 先介绍几个相关函数: int dup2(arg1,arg2):参数一指向的内容赋给参数二,shi的参数二也能访问参数一所指向的内容,并返回新的描述符 int fork()创建子进程,返回值-1:创建失败 返回值0:子进程 返回其他:父进程 setsid()调用成功后&#x…

用aspnet_compiler发布网站 (转载:My way of my life )

在asp.net 2.0模型中&#xff0c;vs2005已经完全脱离了编译而成为了一个彻底的ide.算是一个不小的改动。其中更是取消了有关Web Application的概念&#xff0c;使得习惯了vs2003的人刚开始的时候会有一些摸不着头脑。下面简单说一下我在使用过程中自己总结的&#xff0c;算是一…

react学习(57)--map赋值

<Radio.Group>{linksList?.map((item) > (<Radio key{item.key} value{item.key}>{item.value}</Radio>))}</Radio.Group>

使用 dojo/query

在本篇文章中&#xff0c;我们将了解DOM的查询以及如何运用dojo/query这个模块来轻松地选择节点并操作他们。 入门指南 在操作DOM的过程中&#xff0c;如何快速高效地检索出DOM节点显得相当重要。我们在Dojo DOM Functions中已经熟悉了 dom.byId&#xff0c;然而&#xff0c;在…

【Linux内核】虚拟地址空间布局架构

虚拟地址空间布局架构(Linux内核学习) 1.Linux内核整体架构及子系统 内核对下管理硬件,对上通过运行时库对应用提供服务 用户空间 使用malloc()分配内存通过free()释放内存 内核空间 虚拟进程负责从进程的虚拟地址空间分配虚拟页,sys_brk来扩大或收缩堆,sys_mmap负责在内存映…

天凉了,大家多穿衣服

这两天天气转凉&#xff0c;我还穿夏天的衬衫&#xff0c;结果今晚回来发现喉咙不舒服&#xff0c;只好去买药了。大家要保重身体呀&#xff01;

[开源]C#中开源软件大汇总(外国的)

一、博客类项目 1.SubText 项目介绍&#xff1a;Subtext 是一个个人博客发布平台&#xff0c;详细的介绍请进SubText 项目分类&#xff1a;博客 项目license:BSD License 项目主页&#xff1a;http://subtextproject.com/ 2.BlogEngine.net 项目介绍&#xff1a;详细的介绍请进…

【Linux内核】内存映射原理

【Linux内核】内存映射原理 物理地址空间 物理地址是处理器在总线上能看到的地址,使用RISC(Reduced Instruction Set Computing精简指令集)的处理器通常只实现一个物理地址空间,外围设备和物理内存使用统一的物理空间, 有些架构的处理器把分配给外围设备的物理地址称为设备内存…

react学习(59)--this.props语法糖

{...this.props}是props所提供的语法糖&#xff0c;可以将父组件的所有属性复制给子组件