16延迟回收连接池连接功能
一、框架
// master process ./nginx
// worker process
//(i)ngx_master_process_cycle() //创建子进程等一系列动作
//(i) ngx_setproctitle() //设置进程标题
//(i) ngx_start_worker_processes() //创建worker子进程
//(i) for (i = 0; i < threadnums; i++) //master进程在走这个循环,来创建若干个子进程
//(i) ngx_spawn_process(i,"worker process");
//(i) pid = fork(); //分叉,从原来的一个master进程(一个叉),分成两个叉(原有的master进程,以及一个新fork()出来的worker进程
//(i) //只有子进程这个分叉才会执行ngx_worker_process_cycle()
//(i) ngx_worker_process_cycle(inum,pprocname); //子进程分叉
//(i) ngx_worker_process_init();
//(i) sigemptyset(&set);
//(i) sigprocmask(SIG_SETMASK, &set, NULL); //允许接收所有信号
//(i) g_threadpool.Create(tmpthreadnums); //创建线程池中线程
//(i) g_socket.Initialize_subproc(); //初始化子进程需要具备的一些多线程能力相关的信息
//(i) g_socket.ngx_epoll_init(); //初始化epoll相关内容,同时 往监听socket上增加监听事件,从而开始让监听端口履行其职责
//(i) m_epollhandle = epoll_create(m_worker_connections);
//(i) ngx_epoll_add_event((*pos)->fd....);
//(i) epoll_ctl(m_epollhandle,eventtype,fd,&ev);
//(i) ngx_setproctitle(pprocname); //重新为子进程设置标题为worker process
//(i) for ( ;; ) {
//(i) ngx_process_events_and_timers(); //处理网络事件和定时器事件
//(i) g_socket.ngx_epoll_process_events(-1); //-1表示卡着等待吧
//(i) epoll_wait();
//(i) }. .... //子进程开始在这里不断的死循环
//(i) g_threadpool.StopAll(); //考虑在这里停止线程池;
//(i) g_socket.Shutdown_subproc(); //socket需要释放的东西考虑释放;
//(i) sigemptyset(&set);
//(i) for ( ;; ) {}. //父进程[master进程]会一直在这里循环
二、设计思路
2.1延迟回收目的:
/*
如果客户端【张三】断线,服务器端立即回收连接,这个连接很可能被紧随其后连入的新客户端【李四】所使用,
那么这里就很可能产生麻烦;
a)张三funca();执行10秒,服务器从线程池中找一个线程来执行张三的任务;
b)执行到第5秒的时候,张三断线;
c)张三断线这个事情会被服务器立即感知到,服务器随后调用ngx_close_connection把原来属于张三这个连接池中的连接给回收了;
d)第7秒的时候,李四连上来了,系统会把刚才张三用过的连接池中的连接分配给李四【现在这个连接归李四使用】;
e)10秒钟到了,这个线程很可能会继续操纵 连接【修改读数据】;很可能导致服务器整个崩溃;这种可能性是非常有的;
2.2延迟思想
一个连接,如果我们程序判断这个连接不用了;那么 不 应该把这个连接立即放到空闲队列里,而是 应该放到一个地方;
等待一段时间【60】,60秒之后,我再真正的回收这个连接到 连接池/空闲队列 中去,这种连接才可以真正的分配给其他用户使用;为什么要等待60秒,就是需要确保即便用户张三真断线了,那么我执行的该用户的业务逻辑也一定能在这个等待时间内全部完成;这个连接不立即回收是非常重要的,有个时间缓冲非常重要;这个可以在极大程度上确保服务器的稳定。
2.3两种回收连接
a)立即回收【accept用户没有接入时可以立即回收】
b)延迟回收【用户接入进来开始干活了】;
立即回收:ngx_free_connection();
void CSocekt::ngx_close_connection(lpngx_connection_t pConn)
{
pConn->fd = -1; //官方nginx这么写,这么写有意义; 不要这个东西,回收时不要轻易东连接里边的内容
ngx_free_connection(pConn);
if(close(pConn->fd) == -1)
{
ngx_log_error_core(NGX_LOG_ALERT,errno,"CSocekt::ngx_close_connection()中close(%d)失败!",pConn->fd);
}
return;
}
延迟回收:inRecyConnectQueue(),ServerRecyConnectionThread()
void CSocekt::inRecyConnectQueue(lpngx_connection_t pConn)
{
//ngx_log_stderr(0,"CSocekt::inRecyConnectQueue()执行,连接入到回收队列中.");
CLock lock(&m_recyconnqueueMutex); //针对连接回收列表的互斥量,因为线程ServerRecyConnectionThread()也有要用到这个回收列表;
pConn->inRecyTime = time(NULL); //记录回收时间
++pConn->iCurrsequence;
m_recyconnectionList.push_back(pConn); //等待ServerRecyConnectionThread线程自会处理
++m_totol_recyconnection_n; //待释放连接队列大小+1
return;
}
//处理连接回收的线程
void* CSocekt::ServerRecyConnectionThread(void* threadData)
{
//........
}
//归还参数c所代表的连接到到连接池中,注意参数类型是lpngx_connection_t
void CSocekt::ngx_free_connection(lpngx_connection_t pConn)
{
//因为有线程可能要动连接池中连接,所以在合理互斥也是必要的
CLock lock(&m_connectionMutex);
//首先明确一点,连接,所有连接全部都在m_connectionList里;
pConn->PutOneToFree();
//扔到空闲连接列表里
m_freeconnectionList.push_back(pConn);
//空闲连接数+1
++m_free_connection_n;
/*
if(c->ifnewrecvMem == true)
{
//我们曾经给这个连接分配过内存,则要释放内存
CMemory::GetInstance()->FreeMemory(c->pnewMemPointer);
c->pnewMemPointer = NULL;
c->ifnewrecvMem = false; //这行有用?
}
c->data = m_pfree_connections; //回收的节点指向原来串起来的空闲链的链头
//节点本身也要干一些事
++c->iCurrsequence; //回收后,该值就增加1,以用于判断某些网络事件是否过期【一被释放就立即+1也是有必要的】
m_pfree_connections = c; //修改 原来的链头使链头指向新节点
++m_free_connection_n; //空闲连接多1
*/
return;
}

浙公网安备 33010602011771号