日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UDT协议实现分析——UDT初始化和销毁

發布時間:2024/4/11 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UDT协议实现分析——UDT初始化和销毁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

UDT協議是一個用于在高速Internet上傳輸大量數據的基于UDP的可靠傳輸協議。

我們可以將UDT協議的實現看作一個比較復雜的狀態機。更準確的說,是一個主狀態機,外加多個子狀態機。主狀態機是指協議實現中全局唯一、全局共享的狀態與數據結構,主要對應于CUDTUnited類。子狀態機則是對于一次UDT連接或一個Listening的UDT Server的抽象,是UDT自己創建的Socket抽象,一個與系統socket相似但又不同的概念,主要對應于CUDTSocket和CUDT類。UDT的Socket又可以分為3類,分別是Listening socket,read socket和write socket。盡管實際存在3種類型的socket,它們卻都是由相同的幾個類來表示的,但在這幾個類中,它們卻又都有著自己特有的數據結構/狀態。

后面我們將主要用狀態機的 網絡協議分析方法 來分析UDT。具體而言,會主要從如下的一些方面來分析:

  • 這個協議定義了多少種類型的網絡消息,每種消息的具體格式是什么?

  • 主要的一些動作具體的執行過程,比如建立連接,斷開連接,心跳,丟失數據包的信息反饋等:

  • 這些動作發起方和接受方各需要傳遞多少消息,傳遞什么類型的消息?各個消息的具體含義是什么?每條消息中具體攜帶了些什么信息,每種信息的含義又是什么?每條消息都是在什么時間點發送的?

  • 動作執行過程中發送的每一條消息對于主狀態機的影響有哪些?它會促使主狀態機的狀態作什么樣的轉換?

  • 動作執行過程中發送的每一條消息對于相關聯的具體的一個子狀態機有何種影響?它會促使子狀態機的狀態作什么樣的轉換?

  • 協議層面提供了多少接口,即主狀態機提供的public的,給調用者使用的接口都有哪些,比如startup,shutdown,newSocket,listen等。對于這些接口的調用會對主狀態機的狀態產生什么樣的影響,會促使主狀態機的狀態作什么樣的轉換?
    對于這些接口的調用是否會影響到子狀態機?如果會,又會影響哪些,一個還是多個,對于相應的子狀態機的狀態有些什么樣的影響,會促使它們作什么樣的狀態改變?

  • Socket(即子狀態機)提供給用戶調用的接口有哪些?對每個接口的調用對子狀態機的影響是什么?會促使子狀態機的狀態作什么樣的轉換?
    對于這些接口的調用是否會影響到主狀態機?如果會,又是什么樣的影響?會促使主狀態機的狀態作什么樣的轉換?

  • 狀態機的激勵源:

  • 提供給調用者調用的接口。

  • 從網絡中傳遞進來的消息。

  • 狀態機內部起的一些定時執行的Task或其它的線程等。

  • UDT的初始化與銷毀

    這里從UDT全局初始化及銷毀的部分開始分析。也就是主狀態機的狀態變化。

    在調用UDT庫提供的任何功能之前,需要首先調用UDT namespace的startup()函數來對這個庫做初始化。UDT::startup()函數具體的執行過程如下(src/api.cpp):

    int CUDTUnited::startup() {CGuard gcinit(m_InitLock);if (m_iInstanceCount++ > 0)return 0;// Global initialization code #ifdef WIN32WORD wVersionRequested;WSADATA wsaData;wVersionRequested = MAKEWORD(2, 2);if (0 != WSAStartup(wVersionRequested, &wsaData))throw CUDTException(1, 0, WSAGetLastError()); #endif//init CTimer::EventLockif (m_bGCStatus)return true;m_bClosing = false; #ifndef WIN32pthread_mutex_init(&m_GCStopLock, NULL);pthread_cond_init(&m_GCStopCond, NULL);pthread_create(&m_GCThread, NULL, garbageCollect, this); #elsem_GCStopLock = CreateMutex(NULL, false, NULL);m_GCStopCond = CreateEvent(NULL, false, false, NULL);DWORD ThreadID;m_GCThread = CreateThread(NULL, 0, garbageCollect, this, 0, &ThreadID); #endifm_bGCStatus = true;return 0; }int CUDT::startup() {return s_UDTUnited.startup(); }namespace UDT {int startup() {return CUDT::startup(); }

    UDT::startup()的調用過程為:UDT::startup()-> CUDT::startup() -> CUDTUnited::startup()。

    這個地方我們可以看一下,在UDT中定義全局數據結構管理類——CUDTUnited類對象的方法。從語義上來說,CUDTUnited類對象應該是全局唯一的,通常可以用singleton模式來實現這種全局性和唯一性,或者在類外定義一個static的對象也可以。但在UDT中,考慮到CUDTUnited類并不會被導出給用戶作為接口進行直接調用,而只是會作為UDT實現的一部分,因此不需要擔心調皮的用戶會破壞封裝性;同時,CUDTUnited類提供的接口主要是給CUDT調用的,因而被定義為了CUDT類的private static成員變量(src/core.h):

    private:static CUDTUnited s_UDTUnited; // UDT global management base

    另外我們可以看一下UDT中,類成員變量的命名方式:

  • 最開頭是一個小寫字母,表示變量的作用域,比如s表示靜態成員變量static,m表示類非靜態成員變量member等。

  • 第二個字符是下劃線。

  • 在下劃線之后,是0個、一個、兩個或三個小寫字母,表示變量的數據類型。如果是類(結構)類型變量,沒有這個部分。其它一些常見的用于表示變量數據類型的小寫字符/字符串有,i表示int整型值,b表示bool值,p表示指針類型,ll表示int64_t型值,ull表示uint64_t型值等。

  • 之后則是駝峰方式表示的一個描述變量含義的字符串。

  • 最后,再來具體看一下實際執行初始化的CUDTUnited::startup()函數。在CUDTUnited中用m_iInstanceCount來記錄UDT被引用的次數,每一次調用CUDTUnited::startup()函數時,這個數會被加一,而在調用CUDTUnited::cleanup()函數時,這個數會被減一,以避免重復的初始化,并在UDT沒有被任何部分使用到時執行最終的銷毀動作。這也就要求UDT的使用者,一定要成對地調用UDT::startup()和UDT::cleanup()。

  • CUDTUnited::startup()函數會首先增加m_iInstanceCount,并檢查其值,若m_iInstanceCount在遞增前的大于0,表明UDT已經被初始化過了,直接返回,否則,繼續執行后面的初始化動作。

  • 檢查m_bGCStatus的值,若該值為true,表明UDT已經被初始化,而無需再做進一步的動作,直接返回,為false,則繼續執行初始化。

  • 設置m_bClosing為false,以指示GC線程的狀態。CUDTUnited構造函數中會將此值設置為false,但執行UDT::cleanup()結束時,該值為false。

  • 初始化用于停掉GC線程的mutex和condition,然后創建并執行GC線程CUDTUnited::garbageCollect(void* p)。

  • 設置m_bGCStatus為true,以表明UDT的GC線程已經啟動,UDT已可用,然后返回0。

  • 看完了UDT的初始化過程,再來看UDT的銷毀過程,也就是UDT::cleanup():

    int CUDTUnited::cleanup() {CGuard gcinit(m_InitLock);if (--m_iInstanceCount > 0)return 0;//destroy CTimer::EventLockif (!m_bGCStatus)return 0;m_bClosing = true; #ifndef WIN32pthread_cond_signal(&m_GCStopCond);pthread_join(m_GCThread, NULL);pthread_mutex_destroy(&m_GCStopLock);pthread_cond_destroy(&m_GCStopCond); #elseSetEvent(m_GCStopCond);WaitForSingleObject(m_GCThread, INFINITE);CloseHandle(m_GCThread);CloseHandle(m_GCStopLock);CloseHandle(m_GCStopCond); #endifm_bGCStatus = false;// Global destruction code #ifdef WIN32WSACleanup(); #endifreturn 0; }int CUDT::cleanup() {return s_UDTUnited.cleanup(); }int cleanup() {return CUDT::cleanup(); }

    銷毀過程完全是初始化過程的逆過程。調用過程為UDT::cleanup() -> CUDT::cleanup() -> CUDTUnited::cleanup()。在CUDTUnited::cleanup()中:

  • 遞減m_iInstanceCount,并檢查其值,若m_iInstanceCount在遞減后仍然大于0,表明UDT已還存在其它的使用者,直接返回,否則,繼續執行后面的銷毀動作。

  • 檢查m_bGCStatus的值,若該值為false,表明UDT已經被銷毀,而無需再做進一步的動作,直接返回,為true,則繼續執行銷毀動作。

  • 設置m_bClosing為true,以指示GC線程逐步退出執行。然后signal GCStopCond,以便于在GC線程休眠的時喚醒GC線程。

  • 等待GC線程執行結束,然后銷毀用于停掉GC線程的mutex和condition。

  • 設置m_bGCStatus為false,以表明UDT的GC線程已經被銷毀,UDT已不可用,然后返回0。

  • 總結一下,UDT主狀態機的描述與狀態變化。在CUDTUnited類中,主要用如下的這幾個變量來描述主狀態機的狀態(src\api.h):

    private:volatile bool m_bClosing;pthread_mutex_t m_GCStopLock;pthread_cond_t m_GCStopCond;pthread_mutex_t m_InitLock;int m_iInstanceCount; // number of startup() called by applicationbool m_bGCStatus; // if the GC thread is working (true)pthread_t m_GCThread; #ifndef WIN32static void* garbageCollect(void*); #elsestatic DWORD WINAPI garbageCollect(LPVOID); #endifstd::map<UDTSOCKET, CUDTSocket*> m_ClosedSockets; // temporarily store closed socketsvoid checkBrokenSockets();void removeSocket(const UDTSOCKET u);

    可以發現,依賴于GC線程的狀態,UDT主狀態機主要有4個狀態,分別是INIT,STARTING,RUNNING和CLOSING,在UDT中,主要用m_bGCStatus和m_bClosing這兩個bool類型值來描述。這個狀態機只提供了兩個函數給調用者,以影響這個狀態機的狀態,也就是UDT::startup()和UDT::cleanup()函數。這個狀態機的幾個狀態與m_bGCStatus和m_bClosing值的對應關系,及狀態轉換過程如下圖所示:


    在使用UDT的程序啟動起來時,或者執行了UDT::cleanup()函數之后,可以認為UDT處于INIT狀態,也就是初始狀態。在CUDTUnited的構造函數中,會將m_bGCStatus和m_bClosing這兩個值都初始化為false,而UDT::cleanup()函數結束時,m_bGCStatus的值則為false,m_bClosing的值為true。

    調用了UDT::startup()之后,m_bGCStatus的值仍然為false,m_bClosing的值首先被設置為false,然后啟動garbageCollect線程。garbageCollect線程的啟動需要一定的時間,在這段時間內可以認為UDT主狀態機從INIT狀態轉換到了STARTING狀態。

    UDT::startup()會等待garbageCollect線程啟動,在garbageCollect線程啟動之后,m_bClosing的值仍然為false,m_bGCStatus的值被設置為true,以表示UDT已經可用了。這里可以認為UDT主狀態機從STARTING狀態切換到了RUNNING狀態。

    在UDT主狀態機進入RUNNING狀態之前,用戶是無法創建Sokcet的,也就是還沒有任何的子狀態機被創建,因而還無需考慮這些狀態的轉換對于子狀態機的影響。

    使用UDT傳輸了數據之后,需要調用UDT::cleanup()函數來做清理動作。

    調用UDT::cleanup()之后,m_bGCStatus的值仍然為true,但m_bClosing的值首先被設置為true,garbageCollect線程也會被喚醒。這個時候garbageCollect的處理可能比較復雜,可能已經創建了多個Socket,而Socket所處的狀態可能也多種多樣,因而可能會耗費一些時間。在這段時間內,可以認為UDT主狀態機由RUNNING狀態轉換為了CLOSING狀態。這個狀態轉換會對還在使用的Socket的狀態做一個強制的轉換,也就是說這個轉換對子狀態機的狀態有巨大的影響,但此處先不討論這種影響。

    UDT::cleanup()函數會等待garbageCollect線程清理結束。在garbageCollect線程結束之后,m_bGCStatus被設置為false,以表明UDT不可用。此時m_bGCStatus的值為false,m_bClosing的值為false。可以認為,UDT主狀態機的狀態由CLOSING狀態又回到了INIT狀態。

    可見,UDT主狀態機狀態改變的激勵源,主要有UDT::startup()函數,UDT::cleanup()函數,和garbageCollect線程的執行。

    UDT::startup()和UDT::cleanup()函數中都同時檢查了m_iInstanceCount和m_bGCStatus的值,這里似乎有點多余了。

    Done。

    總結

    以上是生活随笔為你收集整理的UDT协议实现分析——UDT初始化和销毁的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。