【网络编程】实现服务器单例

单例

单例是一种设计模式,它的目的是确保一个类只有一个实例,并且提供全局访问点以访问该实例。

在单例模式中,类只能被实例化一次,以确保所有的对象访问都指向同一个实例。这对于需要共享状态或资源的类非常有用,并且避免了多个类实例引起的资源浪费或冲突的问题。

单例模式通常包含以下几个关键要素:

  1. 私有化构造函数,使得其他类无法直接实例化该类。
  2. 静态成员变量,用于存储类的唯一实例。
  3. 静态方法,用于提供全局访问该实例的接口。

由以上可知,要想实现server_socket的单例,需将server_socket写成一个类。

为什么要将服务器写为单例

  • 提高性能:单例模式只会创建一个实例,因此可以避免创建多个实例时造成的资源浪费,从而提高性能。
  • 简化代码:单例模式可以将服务器的初始化和配置逻辑集中到一个地方,从而简化代码。
  • 提高安全性:单例模式可以避免多个实例之间共享数据,从而提高安全性。

以下是一些具体的例子:

  • Web 服务器:Web 服务器通常是单例的,因为它只需要一个实例来处理所有客户端的请求。
  • 数据库连接池:数据库连接池通常是单例的,因为它只需要一个实例来管理所有数据库连接。
  • 日志系统:日志系统通常是单例的,因为它只需要一个实例来记录所有日志。

当然,将服务器写为单例也有一些缺点:

  • 可扩展性:单例模式不利于扩展,因为它只能有一个实例。
  • 可测试性:单例模式不利于测试,因为它很难模拟多个实例之间的交互。

因此,在决定是否将服务器写为单例时,需要权衡利弊。如果服务器需要高性能、简洁的代码和高安全性,那么单例模式是一个不错的选择。如果服务器需要可扩展性和可测试性,那么单例模式可能不是最佳选择。

  • 确保单例模式是必要的:在决定将服务器写为单例之前,需要确保单例模式是必要的。如果服务器不需要高性能、简洁的代码和高安全性,那么单例模式可能不是最佳选择。
  • 使用合适的单例模式:有两种常见的单例模式:饿汉式单例模式和懒汉式单例模式。饿汉式单例模式在类加载时就创建实例,而懒汉式单例模式在第一次使用时才创建实例。选择合适的单例模式需要根据具体情况进行判断。
  • 考虑可扩展性和可测试性:单例模式不利于扩展和可测试性。在设计单例模式时,需要考虑可扩展性和可测试性。

CServerSocket类

为保证整个程序只有一个CServerSocket,所以将CServerSocket写为一个类,并将类的构造函数、析构函数、复制构造函数、赋值运算符重载都写为private。

在类中声明一个静态变量static CServerSocket* m_instance,并实现静态函数static CServerSocket* getInstance()以获取m_instance。(静态函数没有this指针,无法直接访问普通成员变量,所以将m_instance设为静态的)

class CServerSocket
{
public:
	static CServerSocket* getInstance() {
		if (m_instance == NULL) {//静态函数没有this指针,无法直接访问普通成员变量,所以将m_instance改为静态的
			m_instance = new CServerSocket();
		}
		return m_instance;
	}
private://私有,不允许外部复制
	CServerSocket& operator=(const CServerSocket& ss) {}
	CServerSocket(const CServerSocket& ss) {
		m_sock = ss.m_sock;
		m_client = ss.m_client;
	}
	CServerSocket() {
		if (InitSockEnv() == FALSE) {
			MessageBox(NULL, _T("无法初始化套接字环境,请检查网络设置"), _T("初始化错误"), MB_OK | MB_ICONERROR);
			exit(0);
		}
	};
	~CServerSocket() {
		WSACleanup();
	};

	BOOL InitSockEnv() {
		WSADATA data;
		if (WSAStartup(MAKEWORD(1, 1), &data) != 0){
			return FALSE;
		}
		return TRUE;
	}
	static CServerSocket* m_instance;
};

在主函数中调用getIntance()会报错:无法解析的外部符号。因为m_instance只是声明,没有赋初值。在CServerSocket.cpp中添加以下代码:

//置空   显式初始化
CServerSocket* CServerSocket::m_instance = NULL;

CHelper类

以上代码存在问题,即m_intance不会自动析构。

于是在CServerSocket中新建一个CHelper类,帮助m_instance进行析构。

新建releaseInstance(),用于m_instance的析构。

class CServerSocket
{
public:
	static CServerSocket* getInstance() {...}
private:
	CServerSocket& operator=(const CServerSocket& ss) {}
	CServerSocket(const CServerSocket& ss) {...}
	CServerSocket() {...};
	~CServerSocket() {...};
	BOOL InitSockEnv() {...}

	static void releaseInstance() {
		if (m_instance) {
			CServerSocket* tmp = m_instance;
			m_instance = NULL;
			delete tmp;
		}
	}

	static CServerSocket* m_instance;

	class CHelper {
	public:
		CHelper() {
			CServerSocket::getInstance();
		}
		~CHelper() {
			CServerSocket::releaseInstance();
		}
	};
	static CHelper m_helper;
};

在cpp中添加

//调用构造函数
CServerSocket::CHelper CServerSocket::m_helper;

CServerSocket* pserver = CServerSocket::getInstance();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值