好的!讓我詳細講解一下您項目中的連接池是如何工作的。我會基于您現有的代碼來分析整個工作流程。
Read file: net/ngx_c_socket_conn.cxx
Read file: net/ngx_c_socket_conn.cxx
Read file: net/ngx_c_socket_conn.cxx
Read file: net/ngx_c_socket_conn.cxx
Read file: net/ngx_c_socket_conn.cxx
Read file: net/ngx_c_socket_conn.cxx
Ran tool
Ran tool
Read file: _include/ngx_c_socket.h
Read file: _include/ngx_c_socket.h
Read file: _include/ngx_c_socket.h
現在我來詳細講解您項目中的連接池是如何工作的:
連接池詳細工作原理講解
1. 連接池的核心數據結構
您的連接池使用了三個核心的鏈表來管理連接:
// 連接池的核心數據結構
std::list<lpngx_connection_t> m_connectionList; // 所有連接列表【連接池】
std::list<lpngx_connection_t> m_freeconnectionList; // 空閑連接列表【這里邊裝的全是空閑的連接】
std::list<lpngx_connection_t> m_recyconnectionList; // 將要釋放的連接放這里// 原子計數器
std::atomic<int> m_total_connection_n; // 連接池總連接數
std::atomic<int> m_free_connection_n; // 連接池空閑連接數
std::atomic<int> m_totol_recyconnection_n; // 待釋放連接隊列大小// 互斥鎖
pthread_mutex_t m_connectionMutex; // 連接相關互斥量
pthread_mutex_t m_recyconnqueueMutex; // 連接回收隊列相關的互斥量
2. 連接池的初始化過程
initconnection()
函數詳解
void CSocekt::initconnection()
{lpngx_connection_t p_Conn; // 連接對象CMemory *p_memory = CMemory::GetInstance(); int ilenconnpool = sizeof(ngx_connection_t); // 連接對象大小// 循環創建指定數量的連接對象for(int i = 0; i < m_worker_connections; ++i) {// 1. 分配內存 - 使用自定義內存管理器p_Conn = (lpngx_connection_t)p_memory->AllocMemory(ilenconnpool, true);// 2. 手工調用構造函數 - 因為AllocMemory無法調用構造函數p_Conn = new(p_Conn) ngx_connection_t(); // 定位new// 3. 初始化連接對象p_Conn->GetOneToUse();// 4. 將連接放入兩個列表m_connectionList.push_back(p_Conn); // 所有連接都放在總列表m_freeconnectionList.push_back(p_Conn); // 空閑連接放在空閑列表}// 5. 設置計數器m_free_connection_n = m_total_connection_n = m_connectionList.size();
}
初始化過程的關鍵點:
- 使用定位new技術,因為自定義內存管理器無法調用構造函數
- 每個連接對象都會調用
GetOneToUse()
進行初始化 - 初始時,所有連接都在空閑列表中
3. 連接對象的生命周期管理
連接對象的初始化 - GetOneToUse()
void ngx_connection_s::GetOneToUse()
{++iCurrsequence; // 序號遞增,用于檢測連接是否有效fd = -1; // 開始先給-1curStat = _PKG_HD_INIT; // 收包狀態處于初始狀態precvbuf = dataHeadInfo; // 收包緩沖區指向包頭信息irecvlen = sizeof(COMM_PKG_HEADER); // 先收包頭長度的數據precvMemPointer = NULL; // 接收內存指針iThrowsendCount = 0; // 發送計數psendMemPointer = NULL; // 發送內存指針events = 0; // epoll事件lastPingTime = time(NULL); // 上次ping的時間FloodkickLastTime = 0; // Flood攻擊檢測FloodAttackCount = 0; iSendCount = 0; // 發送隊列數據條目數
}
連接對象的清理 - PutOneToFree()
void ngx_connection_s::PutOneToFree()
{++iCurrsequence; // 序號遞增// 釋放接收數據的內存if(precvMemPointer != NULL) {CMemory::GetInstance()->FreeMemory(precvMemPointer);precvMemPointer = NULL; }// 釋放發送數據的內存if(psendMemPointer != NULL) {CMemory::GetInstance()->FreeMemory(psendMemPointer);psendMemPointer = NULL;}iThrowsendCount = 0; // 重置發送計數
}
4. 連接池的獲取和歸還機制
獲取連接 - ngx_get_connection()
lpngx_connection_t CSocekt::ngx_get_connection(int isock)
{// 加鎖保護,因為可能有多個線程同時訪問CLock lock(&m_connectionMutex); if(!m_freeconnectionList.empty()){// 有空閑連接,從空閑列表中取出lpngx_connection_t p_Conn = m_freeconnectionList.front();m_freeconnectionList.pop_front(); // 從空閑列表移除p_Conn->GetOneToUse(); // 重新初始化連接對象--m_free_connection_n; // 空閑連接數減1p_Conn->fd = isock; // 設置socket文件描述符return p_Conn;}// 沒有空閑連接,創建新連接CMemory *p_memory = CMemory::GetInstance();lpngx_connection_t p_Conn = (lpngx_connection_t)p_memory->AllocMemory(sizeof(ngx_connection_t), true);p_Conn = new(p_Conn) ngx_connection_t();p_Conn->GetOneToUse();m_connectionList.push_back(p_Conn); // 加入總列表++m_total_connection_n; // 總連接數加1p_Conn->fd = isock;return p_Conn;
}
歸還連接 - ngx_free_connection()
void CSocekt::ngx_free_connection(lpngx_connection_t pConn)
{// 加鎖保護CLock lock(&m_connectionMutex); // 清理連接對象pConn->PutOneToFree();// 放回空閑列表m_freeconnectionList.push_back(pConn);// 空閑連接數加1++m_free_connection_n;
}
5. 連接回收機制
延遲回收 - inRecyConnectQueue()
void CSocekt::inRecyConnectQueue(lpngx_connection_t pConn)
{std::list<lpngx_connection_t>::iterator pos;bool iffind = false;// 加鎖保護回收隊列CLock lock(&m_recyconnqueueMutex);// 防止連接被多次放入回收隊列for(pos = m_recyconnectionList.begin(); pos != m_recyconnectionList.end(); ++pos){if((*pos) == pConn) {iffind = true;break; }}if(iffind == true) {return; // 已經存在,不再重復添加}// 設置回收時間并加入回收隊列pConn->inRecyTime = time(NULL); // 記錄回收時間++pConn->iCurrsequence; // 序號遞增m_recyconnectionList.push_back(pConn); // 加入回收隊列++m_totol_recyconnection_n; // 回收隊列大小加1--m_onlineUserCount; // 在線用戶數減1
}
回收線程 - ServerRecyConnectionThread()
void* CSocekt::ServerRecyConnectionThread(void* threadData)
{ThreadItem *pThread = static_cast<ThreadItem*>(threadData);CSocekt *pSocketObj = pThread->_pThis;time_t currtime;int err;std::list<lpngx_connection_t>::iterator pos, posend;lpngx_connection_t p_Conn;while(1){// 每200毫秒檢查一次usleep(200 * 1000);// 如果有待回收的連接if(pSocketObj->m_totol_recyconnection_n > 0){currtime = time(NULL);err = pthread_mutex_lock(&pSocketObj->m_recyconnqueueMutex); lblRRTD:pos = pSocketObj->m_recyconnectionList.begin();posend = pSocketObj->m_recyconnectionList.end();for(; pos != posend; ++pos){p_Conn = (*pos);// 檢查是否到了回收時間if((p_Conn->inRecyTime + pSocketObj->m_RecyConnectionWaitTime) > currtime && g_stopEvent == 0){continue; // 沒到釋放時間} // 檢查是否可以回收if(p_Conn->iThrowsendCount > 0){// 還有未發送完的數據,記錄日志但繼續回收ngx_log_stderr(0,"到釋放時間卻發現iThrowsendCount!=0,這個不該發生");}// 執行回收--pSocketObj->m_totol_recyconnection_n; // 回收隊列大小減1pSocketObj->m_recyconnectionList.erase(pos); // 從回收隊列移除pSocketObj->ngx_free_connection(p_Conn); // 歸還到連接池goto lblRRTD; }err = pthread_mutex_unlock(&pSocketObj->m_recyconnqueueMutex); }// 程序退出時的強制回收邏輯...}return (void*)0;
}
6. 連接池的工作流程圖
初始化階段:
┌─────────────────┐
│ initconnection()│
└─────────┬───────┘│▼
┌─────────────────┐ ┌─────────────────┐
│ m_connectionList│ │m_freeconnectionList│
│ (所有連接) │ │ (空閑連接) │
└─────────────────┘ └─────────────────┘│ │└──────────┬───────────┘│▼┌─────────────────┐│ 連接對象初始化 ││ GetOneToUse() │└─────────────────┘使用階段:
┌─────────────────┐
│ 客戶端連接請求 │
└─────────┬───────┘│▼
┌─────────────────┐
│ngx_get_connection│
└─────────┬───────┘│▼
┌─────────────────┐ ┌─────────────────┐
│ 有空閑連接? │───?│ 從空閑列表取出 │
└─────────┬───────┘ └─────────────────┘│▼
┌─────────────────┐ ┌─────────────────┐
│ 沒有空閑連接? │───?│ 創建新連接 │
└─────────┬───────┘ └─────────────────┘│▼
┌─────────────────┐
│ 連接使用中... │
└─────────┬───────┘│▼
┌─────────────────┐
│ 連接斷開 │
└─────────┬───────┘│▼
┌─────────────────┐ ┌─────────────────┐
│ 立即歸還? │───?│ ngx_free_connection│
└─────────┬───────┘ └─────────────────┘│▼
┌─────────────────┐ ┌─────────────────┐
│ 延遲回收? │───?│ inRecyConnectQueue│
└─────────┬───────┘ └─────────────────┘│▼
┌─────────────────┐
│ 回收線程處理 │
│ ServerRecyConnectionThread│
└─────────────────┘
7. 連接池的關鍵特性
線程安全
- 使用
CLock
類進行互斥鎖保護 - 兩個獨立的互斥鎖:
m_connectionMutex
和m_recyconnqueueMutex
內存管理
- 使用自定義內存管理器
CMemory
- 定位new技術確保構造函數正確調用
- 顯式調用析構函數進行清理
延遲回收機制
- 連接不會立即回收,而是放入回收隊列
- 等待指定時間后才真正回收,確保服務器穩定
- 專門的回收線程定期檢查和處理
序號機制
- 每個連接對象都有
iCurrsequence
序號 - 每次分配和回收時序號遞增
- 用于檢測連接是否有效,防止使用已回收的連接
動態擴展
- 當空閑連接不足時,會自動創建新連接
- 連接池大小可以動態增長
這個連接池設計非常完善,既保證了性能,又確保了線程安全和資源管理的正確性。