网络资源的初始化与释放(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采用智能指針也可以實現單例模式,以后可能會介紹
總結
以上是生活随笔為你收集整理的网络资源的初始化与释放(C++ RAII惯用法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用VUE分分钟写一个验证码输入组件
- 下一篇: C++变长参数模板