Select模型设计200人服务器
问题描述:
利用select模型设计能够同时支持200人在线的服务器框架
核心难点:
1. select模型缺省情况下最多能支持64人同时在线
2. 如何精确控制在线人数不超过200人
解决思路:多线程处理:
1. 主线程负责接收客户端连接
2. 子线程负责与客户端进行通信,每个线程最多处理64个客户请求
数据维护:
1. 主线程负责服务器逻辑控制,维护服务器数据对象,其具体实现见服务器对象类(CService设计)设计
2. 每个子线程负责维护一个线程对象数据类型其类型,其具体类型见线程数据对象类(CThreadObj)设计
*/
主函数代码
#include "stdafx.h"
#include "Service.h"
#include "../InitSocket.h"
CInitSocket g_InitLib;
int main()
{
CService Serv(4567);
Serv.RunServ();
return 0;
}
服务器类设计
/*
CService对象设计
1. 数据对象
1) 监听套接字
2) 端口
3) IP
4) 线程对象列表
2. 数据处理方法
1)服务器初始化(创建套接字,绑定套接字,监听套接字)
2)运行服务器
(接收到客户连接,将通信套接字交给对应线程对象,
如果线程对象没有启动,则启动对应的线程)
- 成功接收连接
- 是否有空余线程对象
否 创建新的线程对象,加入列表,启动线程
是 将套接字交给新的线程
- 线程是否启动 否 启动想成
是 next
*/
#include "ThreadObj.h"
class CService
{
public:
CService();
CService(USHORT uPort, const char *pszIP = NULL);
~CService();
public:
//初始化服务器
bool InitServ(USHORT uPort, const char *pszIP = NULL);
//运行服务器
bool RunServ();
private:
//监听套接字
SOCKET m_sListen;
//服务器端口号
USHORT m_uPort;
//服务器IP
ULONG m_uIP;
//服务器线程列表
list<CThreadObj> m_ThreadList;
};
线程对象设计
/*
线程对象类设计思路
1. 每个线程负责维护的数据对象
1) 当前线程需要处理的socket集合
2) 当前线程socket数量
3) 当前系统socket总数
4) 当前线程是够正在运行
2. 数据处理方法
1) 套接字集合处理方法
增,删,改,查,清空,
2) 判断方法
是否为空,是否已满,线程是否运行
3)Get方法
获取自身引用,获取线程socket总数,获取系统socket总数
3. 运算符重载
1) [] 获取指定索引位置的socket集合对应的socket对象
2) += 添加socket
3) == 对象是否相等,对应的socket是否在集合中
4) -= 移除对象
4. 构造函数
缺省构造 需要
类型转换构造 需要(SOCKET s)
拷贝构造 不需要
移动构造 不需要
其他构造 不需要
*/
class CThreadObj
{
public:
CThreadObj();
~CThreadObj();
private:
// 当前线程套接字集合
fd_set m_fdCurThreadClient;
// 当前线程套接字总数
int m_CurThreadCount;
// 当前系统套接字总数
static int m_nSysTotal;
// 当前线程是否启动
bool m_bThreadRun;
public:
// 向当前线程中添加套接字 s
bool AddSocket(SOCKET s);
//从当前线程中移除套接字 s
bool RemoveSocket(SOCKET s);
// 判断套接字是否在当前线程
bool IsSet(SOCKET s);
// 当前线程套接字是否为 0
bool IsEmpty();
// 当前系统套接字是否已满
bool IsFull();
// 当前线程是否正在运行
bool IsRun();
// 获取当前线程套接字数量
int GetCount();
//启动线程
bool RunThread();
//获取当前系统对象的引用
CThreadObj& GetThreadObj();
private:
// 清空当前线程中套接字,析构或者异常时候使用
bool Clear();
// 获取系统套接字总数
static int GetTotal();
private:
// 线程过程函数
static DWORD WorkItemFun(PVOID lParam);
};
具体实现见上传文件