![](https://csdnimg.cn/release/download_crawler_static/34060385/bg1.jpg)
激发线程来处理
Nginx(仿)
main排布
(0)先初始化的变量
(1)无伤大雅也不需要释放的放最上边
(2)单例类初始化
配置文件单例类
内存单例类
crc32 校验算法单例类
(3)日志初始化
(4)一些初始化函数
(5)不好归类的函数
比如环境变量搬家
(6)创建守护进程
(7)正式主工作流程
ngx_master_pr ocess_cycle()
ngx_worker_ process_cycle()子进程功能函数
子进程 初始化ngx_worker_proces s_init();
放开信号集屏蔽
创建线 程池中线程 g_threadpool.Crea te()
创建m_ iThread Num个线程,并推入容器中
线程入 口函数: pthread_create(&pNew->_Handle, NULL, ThreadFunc, pNew);
初始化 一些多 线程能力相关 g_socket.Initialize_subproc()
子进程中才需要执行的初始化函数
发消息 互斥量 、连接相 关互斥 量、连接 回收队 列相关互 斥量、 时间处理队列有关的互斥量初始化,初始化发消息相关信号量
创建专门用来发送数据的线程
线程入 口函数ServerSendQueueThread ()
创建专门用来回收连接的线程
线程入 口函数ServerRecyConnectionThread()
创建专 门用来处理到期不发心跳包的用户踢出的线程
线程入 口函数Ser verTimerQueueMonitorThread()
epoll 技术:g_socke t.ngx_epoll_init();
创建epoll 对象,ep oll_create()
创建连 接池,initconnection();
分配内存 (lpn gx_c onne ction_t)p_memory->AllocMemory(ilenconnpool,true);
所有链 接【不 管是否空 闲】都放在这个 list ,m_connectionList.push_back(p_Conn);
空闲连 接会放 在这个lis t,m_freeconnectionList.push_back(p_Conn);
遍历所 有监听sock et【监听端口】
从连接 池中获 取一个空 闲连接 对象(监 听套接字连接)ngx_get_connection()
增加监 听事件CSocekt::ngx_epo ll_oper_event()
系统函 数epoll_ctl()
p_Conn->rhandler = &CSocekt::ngx_event_accept
对监听 端口的 读事件设 置处理方法ngx_event_accept()
ac cept4()和accept()
从连接 池中获 取一个空 闲连接 对象(客 户端套接字连接) ngx_get_connection()
增加读 写事件CSocekt::ngx_epo ll_oper_event()
系统函 数epoll_ctl()
newc->rhandler = &CSocekt::ngx_read_re quest_handler; 设置数 据来时 的读处理函数 ngx_read_request_handler()
newc->whandler = &CSocekt::ngx_write_request_handler ; 设 置数据来 时的写 处理函数ngx_write_request_handler()
设置子 进程的标题 ngx_setproctitle()
设置标 题作用 :在查看系统进程是可以看到独有的进程名,好区分
子进程 死循环 ,处理网 络事件 和定时器事件,ngx_process _events_and_timers();
开始获 取发生 的事件消息g_socke t.ngx_epoll_process_events();
系统函 数epoll_wait()
没事件 无限等 待,有事件走到下面,循环遍历所有事件
如果是 读事件if(revents & EPOLLIN )
(this->* (p_Conn->rhandler) )(p_Conn);
如果是 写事件if(revents & EPOLLOUT)
(this->* (p_Conn->whandler) )(p_Conn);
统计信 息打印g_socket.printTDInfo();
ngx_master_pr ocess_cycle()主工作流程
(1)信号集初始化及设置
(2)设置 主进程 标题ngx_setproctitle()
设置标 题作用 :在查看系统进程是可以看到独有的进程名,好区分
(3)创建 子进程ngx_start_worker _processes();
几个子 进程就执行 ngx_ spawn_process(i,"work er process ")多少次
在fork 之后子进 程中返回 的是0 ,并执行ngx_worker_process_cycle();
而原来 的主进 程中返回 的是新建进程的 pid,并直接返回
(4)主进程死循环,只依靠信号来驱动
CThreadPool:: ThreadFunc()线程入口函数
线程入口参数的理解
线程进入死循环
没有拿到消息队列中的数据 或者 m_shutdown == false ,在下面的地方等待
保证每 个线程 都启动并运行到 pt hrea d_cond_wait(),OK 是,主线程返回
pthread_cond_wait (&m_pthreadCond, &m_pthreadMutex )
拿到了真正的消息队列中的数据 或者 m_shutdown == true,下面消息处理
在消息 队列中 取出一则消息, char *jobbuf = pThread PoolObj->m_MsgRecvQueue.front();
处理取 得的消息: g_socket.threadRecvProcFunc(jobbuf)
ngx _re ad_req uest_handler()设置数据来时的读处理函数
下面是 对于数 据包的接收和处理,列出典型的几个函数
后续逻辑再说
接收数 据专用函数 recvproc()
系统调 用函数recv()
包头收 完整后 的处理ngx_wait_request_handler_proc_p1()
包体接 收处理函数 ngx_wait_request_handler_proc_plast()
内部有 主要函数 inMsgRecvQueueAndSignal()
入消息 队列m_MsgRecvQueue.push_back(buf);
激发一 个线程 来干活Call();
核心p thread_cond_signal(&m_pthreadCond) 线程处理是怎么处理消息队列中的消息的呢
并且判断是否还有可用线程可调度
Se rver SendQueueThread() 处理发送消息队列的线程
(技术)信号量的通信方式
发送线 程信号 量(等待操作) sem_wait()
发送队 列中一 则数据包 的发送(循环) while(pos != posend)
剪切消息,只发送包头+包体数据包
直接调 用write或 者send发送 数据,pSo cketObj->sendproc()
成功发 送出去了数据,一下就发送出去这很顺利
没有全 部发送 完毕(EAG AIN),数据只发出去了一部分,但肯定是因为 发送缓冲区满了
将依靠ep oll驱动 调用ng x_wr ite_re quest_handler()函数发送数据
CSocekt::ngx_epoll_oper_event()
发送缓冲区已经满了【一个字节都没发出去】
也是把 发送的 消息放在epoll 中
要发送 的东西 也要从发 送队列里干掉 pSocketObj->m_MsgSendQueue.erase (pos2);
Se rver Re cyConnectionThread()处理连接回收的线程
主动关闭一个连接时的要做些善后的处理函数 ,CSocekt::zdCloses ocketProc()
什么时候去调用这个函数
心跳包 检测时 间到了CLog icSocket::procPingTimeOutChecking()
检测到 Flood攻击 ,ngx_read_request_handler()
接收数 据专用 函数,CSocekt::recvproc()
累积的 该用户 的发送队 列中有 的数据条 目数过大时,CSocekt::msgSend()
连接进 回收连 接队列中,CSocekt::inRecyConnectQueue()
等待S er verR ecyConnectionThread 线程自会 处理,m_ recyconnectionList.push_back(pConn);
待释放 连接队 列大小+1,++ m_totol_recyconnection_n;
释放、归还连接
当有需 要释放的连接时,就不停的一个一个的释放掉
释放流程,及重要步骤
待释放 队列减 一,--pS ocketObj->m_totol_recyconnection_n;
擦除指 向的内存, pSock etObj->m_recyconnectionList.erase(pos);
归还连 接到连 接池中,p Soc ketObj->ngx_free_connection(p_Conn);
扔到空 闲连接 列表里,m_ freeconnectionList.push_back(pConn);
要退出整个程序时
硬释放,同箭头指向
时间队 列监视 和处理线程ServerTimer QueueMonitorThread()
其他相关函数
清理时 间队列 中所有内容, CSocekt::clearAllFromTimerQueue()
把指定 用户tcp 连接从timer 表中抠出 去,CS oce kt::DeleteFromTimerQueue(lpngx_connection_t pConn)
程序不 退出, 就一直执 行下面内容while(g_stopEvent == 0)
一次性 的把所 有超时节 点都拿过来,pSo cketObj->GetOverTimeTimer()
检查心 跳超时 问题,pS ock etOb j->procPingTimeOutChecking(tmpmsg,cur_time);
CLogicSocket::procPingTimeOutChecking ()
CLogicSo cket::threadRecv ProcFunc()处理收到的数据包
对于数 据包的 处理都要crc32 校验OK
没有包体,只有包头的数据包处理
含包体数据包处理,要做一些判断
客户端是否断线
消息码是否正确
是否有对应的消息处理函数
放心大胆的处理(真正的处理数据包)
调用消息码对应的成员函数来处理
(this->*statusHandler[])();
(技术)用来保存 成员函数指针 的数组
&CL ogi cSo cke t::_HandlePing,//【0】:心跳包的实现 CLogicSocket::_HandlePing ()
msgSend(p_sendbuf);
服务器 做好发 给客户端 的数据 包并发送出去CSocekt::msgSend(char *ps endbuf)
将一个待发送消息入到发消息队列
数据包 推进发 送队列中m_MsgSendQueue.push_back(p sendbuf);
发送队 列的信 号量(加 1操作)sem_post(&m_semEventSendQueue)
将信号 量的值 +1,这 样其他卡在se m_wait的就可以走下去
&CL ogi cSo cke t::_HandleRegister,//【5】:实现具体的注册功能
CLogicSocket::_HandleRegister ()
msgSend(p_sendbuf);
&CL ogi cSo cke t::_HandleLogIn,//【6】:实现具体的登录功能
CLogicSocket::_HandleLogIn ()
作为回 应CLogicSocket::SendNoBo dyPkgToClient ()
上面函 数也包 含函数msgSend(p_sendbuf);
ngx _wri te_reques t_handler()设置数据来时的写处理函数
发送数 据专用函数 sendproc()
系统调 用函数send()
对于上 面这函数,成功发送了数据,则需要调用
ngx _ep oll_oper_event在ep oll清除该事件
发送队 列的信 号量(减 1操作)sem_pos t(&m_semEventSendQueue) --p Con n->i ThrowsendCount;//这 个值恢复了,触发下面一行的信号量才有意义
Nginx.mmap - 2021/10/19 - 1448915713@qq.com