游戏服务器之被动连接线程池

本文内容是游戏服务器之被动连接线程池。顾名思义,被动连接线程池处理的是被动连接的会话的状态管理和数据收发。


设计上:

每个服务器对象有个接收连接线程池, 线程类型包括:

验证线程、同步线程、网络接收发送线程、回收线程。

会话正常流程步骤(正常状态切换流程):

(1)程序主线程接收连接(监听连接)

(2)验证线程(检查验证超时、验证发来消息的服务器id和服务器ip(服务器之间,依靠中心服务器发来的依赖服务器列表)、验证账号和临时id和账号(客户端登陆和重登陆))

(3)同步线程(网关发消息删除中心服务器登陆会话,中心服务器读数据库检查其他服务器连接的合法性、发送测试消息到对端)

(4)网络接收发送线程

(5)回收线程(回收连接)


 


本文内容:

1、被动连接线程池初始化

初始化是在进程主线程的服务器对象(具体服务器类对象)的初始化函数里。

线程类型包括:回收线程、验证线程、同步线程、网络接收发送线程(网络接收发送线程也是根据配置有多个)。


 线程池初始化

创建线程:
回收线程 1 个,验证线程 2个,同步线程1个,业务网络数据接收发送线程 随不同服务器而变化(网关4个,场景1个等)
bool tcp_session_pool::init()
{
	//创建回收线程
	if(!recycleThreads.init(1,1,"recycle_thread",this))
	{
		g_log->debug("recycle_thread线程启动失败");
		return false;
	}
	
	//创建初始化验证线程
	if(!verifyThreads.init(1,2,"verify_thread",this))//检查验证超时、中心服务器的服务器配置验证(读数据库)
	{
		g_log->debug("verify_thread线程启动失败");
		return false;
	}
	
	//创建初始化同步线程
	if(!syncThreads.init(1,1,"sync_thread",this))
	{
		g_log->debug("sync_thread线程启动失败");
		return false;
	}
	
	//创建初始业务网络数据接收发送线程(这里的网络接收发送线程只是处理网络接收和发送的线程)
	int maxThreadCount = (maxConns + main_service_thread::getMaxSize() - 1)/main_service_thread::getMaxSize();
	g_log->debug("线程最大连接数%d,每线程连接数%d,线程个数%d",maxConns,main_service_thread::getMaxSize(),maxThreadCount);
	if(!okayThreads.init(1,maxThreadCount,"main_service_thread",this))
	{
		g_log->debug("main_service_thread线程启动失败");
		return false;
	}
	return true;
}



2、被动连接池的会话管理

连接的状态处理是由线程池的那些状态管理线程来处理的,连接的状态会进行转换,把连接对象交给其他线程来管理。

(1)未使用会话到验证线程

bool tcp_session_pool::addVerify(tcp_session *task)
{
	verify_thread *pThread = verifyThreads.getOne();
	if(pThread)
	{
		/*
		* cjy
		*state_notuse -> state_verfy 
		* 先设置状态再添加容器,
		* 否则会导致一个task同时在两个线程中的危险情况
		*/
		task->getNextState();
		pThread->add(task);
	}
	else
	{
		g_log->error("没有找到验证线程添加任务");
	}
	return true;
}

(2)验证会话到同步线程

void tcp_session_pool::addSync(tcp_session *task)
{
sync_thread *pThread = syncThreads.getOne();
if(pThread)
{
// state_verify-> state_sync
/*
* cjy
* 先设置状态再添加容器
*/
task->getNextState();
pThread->add(task);
}
else
{
g_log->error("没有找到回收线程添加任务");
}
}


(2)同步会话到网络收发线程

bool tcp_session_pool::addOkay(tcp_session *task)
{
	main_service_thread *pThread = okayThreads.getOne();
	if (pThread)
	{
		// state_sync -> state_okay
		/*
		* cjy
		* 先设置状态再添加容器,
		*/
		task->getNextState();
		pThread->add(task);
		return true;
	}
	
	g_log->fatal("没有找到主线程添加任务");
	//没有找到线程来处理这个连接,需要回收关闭连接
	return false;
}

(3)会话到回收线程

void tcp_session_pool::addRecycle(tcp_session *task)
{
recycle_thread *pThread = recycleThreads.getOne();
if(pThread)
{
pThread->add(task);
}
else
{
g_log->error("没有找到回收线程添加任务");
}
}

3、网络数据收发

业务网络收发线程的循环部分,处理网络数据的接收和发送。
设计上:

(1)先检查所有连接是否处于正常状态。

(2)网络的处理是读优先的,有读才检查写,写的检查是一段时间检查一次(目前是50ms)。

实现上通过两个epoll描述符来处理。
第一个epoll描述符监听所有连接的读事件,并处理网络数据的接收。

第二个epoll描述符监听所有连接的写事件(顺带会检查读事件),并处理网络数据的发送(顺带会处理有读事件的连接的接收)。



详细查看

http://blog.csdn.net/chenjiayi_yun/article/details/31765803


4、服务器关闭销毁连接池线程和epoll句柄资源

 

server_base::~server_base()
{
	if (taskPool)//回收连接池,关闭连接管理和收发的线程
	{
		taskPool->final();
		SAFE_DELETE(taskPool);
	}
	//关闭epoll句柄
	TEMP_FAILURE_RETRY(::close(epoll_handler));
	if (-1 != sock_handler) 
	{
		::shutdown(sock_handler, SHUT_RD);//<span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">关闭sockfd上的读功能,此选项将不允许sockfd进行读操作</span>
		TEMP_FAILURE_RETRY(::close(sock_handler));
		sock_handler = -1;
	}
}


连接池删除时需要关闭所有这些线程

void tcp_session_pool::final()
{
	g_log->debug("%s", __PRETTY_FUNCTION__);
	verifyThreads.final();
	syncThreads.final();
	okayThreads.final();
	recycleThreads.final();
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值