UDT 最新源码分析(二) -- 开始与终止
生活随笔
收集整理的這篇文章主要介紹了
UDT 最新源码分析(二) -- 开始与终止
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
UDT 最新源碼分析 -- 開始與終止
- UDT 開始與終止
- 開始流程
- 終止流程
UDT 開始與終止
開始流程
UDT:: startup -> CUDT::startup -> CUDTUnited::startup
初始化UDT庫,多次調用時,調用計數增加,但實際上僅僅初始化一次。對于windows下,還需要初始化網絡庫WSAStartup。建立 garbageCollect 線程,用于清理失效socket,并刪除分發器。
int CUDTUnited::startup() {CGuard gcinit(m_InitLock); //獲取初始鎖if (m_iInstanceCount++ > 0) //實例被初始化的計數器,僅初始化一次return 0;if (m_bGCStatus) //garbageCollect狀態,保證線程不會被建立多個return true;m_bClosing = false; //CUDTUnited狀態, 此狀態下 garbageCollect內 while循環不退出pthread_mutex_init(&m_GCStopLock, NULL);pthread_cond_init(&m_GCStopCond, NULL);pthread_create(&m_GCThread, NULL, garbageCollect, this); //garbageCollect 線程創建m_bGCStatus = true;return 0; }再來看 garbageCollect:
void* CUDTUnited::garbageCollect(void* p) {CUDTUnited* self = (CUDTUnited*)p; //獲取CUDTUnited實例,類型轉化CGuard gcguard(self->m_GCStopLock);//資源清理的鎖while (!self->m_bClosing) //初始 m_bClosing = false,無限循環{//當UDT協議判斷某一個UDT SOCKET的狀態不正確時,會將其狀態設置為BROKEN,并在這個函數中進行處理self->checkBrokenSockets();//睡眠等待,等待下一次可以清理出現BROKEN狀態的UDT SOCKET。睡眠時間 timeout: 1spthread_cond_timedwait(&self->m_GCStopCond, &self->m_GCStopLock, &timeout);}//remove all sockets and multiplexers. m_bClosing = true, 清理目前依舊殘余的資源 CGuard::enterCS(self->m_ControlLock);//遍歷 m_Sockets 中的 UDT socket,設置為關閉,存入 m_ClosedSockets map,下一步處理連接記錄。//查找 Listener, 將 該socket 在Listener中的 m_pQueuedSockets 與 m_pAcceptSockets中記錄刪除for (map<UDTSOCKET, CUDTSocket*>::iterator i = self->m_Sockets.begin(); i != self->m_Sockets.end(); ++ i){i->second->m_pUDT->m_bBroken = true; //將CUDT* 的狀態設置為 BROKEN,后續進行處理i->second->m_pUDT->close(); //關閉i->second->m_Status = CLOSED;//設置狀態為關閉i->second->m_TimeStamp = CTimer::getTime(); //調整最后一次操作 UDT socket 的時間self->m_ClosedSockets[i->first] = i->second;//將當前描述連接的CUDT*保存至 m_ClosedSockets// remove from listener's queuemap<UDTSOCKET, CUDTSocket*>::iterator ls = self->m_Sockets.find(i->second->m_ListenSocket);if (ls == self->m_Sockets.end()) //如果沒有找到Listener, m_ClosedSockets中繼續查找{ls = self->m_ClosedSockets.find(i->second->m_ListenSocket);if (ls == self->m_ClosedSockets.end()) //如果沒有找到,就不再處理continue;}CGuard::enterCS(ls->second->m_AcceptLock);//獲取Listener中的鎖ls->second->m_pQueuedSockets->erase(i->second->m_SocketID);//清理接收連接但還未接受的排隊 UDT socketls->second->m_pAcceptSockets->erase(i->second->m_SocketID);//清理已完成連接的隊列中UDT socketCGuard::leaveCS(ls->second->m_AcceptLock);}self->m_Sockets.clear();//最后刪除m_Sockets中的所有sockets//最后再次遍歷待關閉的socket隊列for (map<UDTSOCKET, CUDTSocket*>::iterator j = self->m_ClosedSockets.begin(); j != self->m_ClosedSockets.end(); ++ j){j->second->m_TimeStamp = 0;//設置狀態為 0}CGuard::leaveCS(self->m_ControlLock);while (true){//之前只是將即將清理的UDT socket 狀態設置為BROKEN,此時對BROKEN狀態的socket進行清理self->checkBrokenSockets();CGuard::enterCS(self->m_ControlLock);bool empty = self->m_ClosedSockets.empty(); //判斷待關閉socket是否已經全部清理CGuard::leaveCS(self->m_ControlLock);if (empty)//如果為empty,就可以直接退出break;CTimer::sleep();//不行的話,再歇一會,再次進行處理}return NULL; }上面代碼中出現了兩次 checkBrokenSockets,該方法用于清理處于BROKEN狀態的 UDT socket。
- 檢查所有的 UDT socket
- 如果不是處于broken狀態,查找下一個,如果處于broken狀態:
- 如果 socket 處于 LISTENING 狀態,須再等待3s,以防止有客戶端正在連接
- 如果 recvbuffer 存在數據,且 brokencount 計數器仍大于0,繼續等待更長的時間
- 否則:
- 設置socket為CLOSED狀態,更新 m_TimeStamp 為當前時間, 開啟移除定時器。
- 將當前socket加入待關閉 tbc vector, socket加入臨時存儲closed socket的 m_ClosedSockets map.
- 查找 Listener, 從m_pQueuedSockets 和 m_pAcceptSockets 移除接收到的socket 連接 socket。
- 如果不是處于broken狀態,查找下一個,如果處于broken狀態:
- 對于移入臨時存儲待關閉的 m_ClosedSockets map,檢查每個socket,
- 如果 m_ullLingerExpiration > 0,表示在發送緩沖中存在數據時,GC設置了延遲關閉的時間
- 如果發送緩沖不存在,或為空,或設置關閉時間已經超時:
- 將m_ullLingerExpiration設置為0;設置UDT socket為關閉狀態,在下一次GC中將被回收。更新關閉時間為當前時間。
- 如果發送緩沖不存在,或為空,或設置關閉時間已經超時:
- 否則:
- 如果標記關閉時間已經超過1s,且socket對應接收隊列信息節點已經被刪除,或者節點不存在list中
- 將UDT socket加入tbr 移除隊列
- 如果 m_ullLingerExpiration > 0,表示在發送緩沖中存在數據時,GC設置了延遲關閉的時間
- 遍歷tbc,從 m_Sockets中刪除。遍歷tbr, 將這些超時的 socket 移除。
如果 m_ClosedSockets 中UDT socket 已經超過超過1s, 就會放入 tbr。遍歷 tbr, 移除所有socket,更新相關資源。這里用到了removeSocket 方法。
- 如果UDT socket 是一個 Listener,將所有收到的但未接受的socket 關閉,設置為 BROKEN 狀態,等待移除。
- 刪除 m_PeerRec 中記錄的連接。
- 刪除 UDT socket, 檢查對應的復用器,計數器減一,如果已經為0, 則關閉channel,清理復用器內的資源。
終止流程
- UDT::cleanup -> CUDT::cleanup -> CUDTUnited::cleanup
終止流程與開始流程相反,在計數器清零以后才會真正退出,每次調用,計數減一。修改 m_bClosing 與 m_bGCStatus 狀態,終止垃圾回收線程。
int CUDTUnited::cleanup() {CGuard gcinit(m_InitLock);if (--m_iInstanceCount > 0) //計數器減一return 0;if (!m_bGCStatus) return 0;m_bClosing = true;pthread_cond_signal(&m_GCStopCond);pthread_join(m_GCThread, NULL);pthread_mutex_destroy(&m_GCStopLock);pthread_cond_destroy(&m_GCStopCond);m_bGCStatus = false;return 0; }對UDT庫的初始化與終止流程分析結束,在例程中,基本上都是顯示調用這兩個接口,但是在 appclient.cpp 中,通過構造函數與析構函數隱式完成。兩種方式均可,可根據需要自選。
struct UDTUpDown{UDTUpDown(){// use this function to initialize the UDT libraryUDT::startup();}~UDTUpDown(){// use this function to release the UDT libraryUDT::cleanup();} };總結
以上是生活随笔為你收集整理的UDT 最新源码分析(二) -- 开始与终止的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java phpwind_GitHub
- 下一篇: 强迫症才需要看,新装电脑 Win10 硬