IPerf——網路測試載入器介紹與源碼解析(2)

來源:互聯網
上載者:User

標籤:

對於IPerf源碼解析,我是基於2.0.5版本在Windows下執行的情況進行分析的,提倡開始先通過對源碼的簡單修改使其能夠在本地編譯器運行起來,這樣可以列印輸出一些中間資訊,對於理解源碼的邏輯,程式實現的過程能夠起到事半功倍的效果。

IPerf主要分為如下幾個模組:

  • 選項參數處理;
  • 線程封裝和角色扮演;
    • 四種線程模式(或者說角色):
      • 用戶端線程;
      • 服務端線程;
      • 報告者線程;
      • 監聽者線程。
  • 通訊端選項設定與提取;
  • 鏈表和數組的封裝和維護;
  • 處理多並發Condition條件變數的封裝;
  • 時間戳記封裝;
  • Windows下作為後台服務啟動並執行建立和運行。

下面儘可能針對每個模組進行說明:

選項參數的處理:

作為命令列控制台應用程式,首要考慮到的問題就是對輸入參數命令列選項的處理,如果是簡單的應用程式直接通過case-switch或者if條件陳述式或許可以解決,但是一旦到了規模較大,實現內容較為複雜的控制台應用程式,比如IPerf,還是用該處理方法就顯得相對笨拙,在效能、邏輯處理等方面都有所不及。

對於選項參數的處理,IPerf使用的GUN的一個getopt檔案,在Linux下已有該標頭檔,而在Windows需要自己匯入該標頭檔和實現檔案,加入檔案之後,還需要做的就是對檔案中的一些長選項和短選項字串進行處理,因為這是自己定義的需求,處理選項參數的邏輯是一定的,但是要將哪些內容作為合理的選項和參數以及運算元,那些又是非法的字元和未能識別的運算元,程式需要據此進行判斷,所以需要進行一個初始化的過程,後面在使用的過程中調用相應的介面對主函數傳進來的args和argv[]作為輸入參數進行處理就行了,更多關於選項參數的處理,可以看看該篇文章,或者自行網上找尋。

 

程式的主要模組就是角色線程的產生、運行和銷毀,其他模組包括時間戳記、條件變數、維護的鏈表等都是為此服務的,所以這裡打算先說一下其他模組然後在逐一分析不同類型的線程。

 

通訊端選項的封裝和設定:

說通訊端選項之前還需要先說一下通訊端的產生,IPerf對通訊端Socket的組建定義了一個名為WIN32Socket的宏,這個宏內部調用了WSASocket,而通訊端的屬性和協議類型是通過定義WSAPROTOCOL_INFO類型靜態函數,並將該函數作為輸入參數傳到WASSocket實現的。

PerfSocket.cpp中只有一個名為SetSocketOptions的函數,顧名思義就是用來設定通訊端選項的值,函數裡麵包含設定TCP滑動視窗大小(setsock_tcp_windowsize函數在另一個名為tcp_window_size.c的檔案中單獨實現)、設定擁塞控制、設定多播、設定IP服務類型(這個很少用得到)、設定最大報文段大小(setsock_tcp_mss函數在sockets.c檔案中實現)、設定非延遲等。當然,除了設定通訊端選項外,也有擷取相應選項的函數,比如getsock_tcp_windowsize和getsock_tcp_mss。

在SocketAddr.c檔案中,IPerf定義了一系列以“SocketAddr_函數功能”格式命名的函數,通過宏條件判斷是否支援IPV6,定義了包括:通過IP地址擷取到或者說轉換成對端的通訊端地址結構,將網路序轉成點分十進位,擷取和設定連接埠值等,圍繞著定義的iperf_sockaddr類型(IPV4下為sockaddr_in類型,IPV6下為sockaddr_storage)判斷該通訊端地址是否相同等。

 

鏈表和數組的維護和封裝:

IPerf在實現中建立了幾種不同類型的鏈表和數組:在開始時的線程鏈表,報告使用的報告者首部鏈表,監聽(者)線程維護的用戶端鏈表,緊接在傳送類型報告者首部後面的包數組,在服務端和多並發用戶端維護的多組報告首部維護的傳輸資訊數組。具體的接下來會詳細講述到,List.cpp封裝對Iperf_ListEntry類型鏈表的增刪查和銷毀操作,而該鏈表僅是監聽者用來儲存和維護已串連用戶端的資訊,別無它用。

 

處理多並發Condition條件變數的封裝:

Condition是IPerf自己封裝的結構體,變數mCondition為事件核心對象的控制代碼,變數mMutex為互斥量的控制代碼,

Condition_Initialize( Cond ): 建立一個初始化就處於觸發狀態的互斥量並把返回的控制代碼值賦予mMutex,建立一個初始化為未觸發狀態的手動重設事件並把返回的控制代碼值賦予mCondition;

Condition_Destroy( Cond ):通過mCondition和mMutex的控制代碼值銷毀事件核心對象和互斥量;

Condition_Lock( Cond )  == Mutex_Lock( &Cond.mMutex ) == WaitForSingleObject( Cond.mMutex, INFINITE )

Condition_Unlock( Cond ) == Mutex_Unlock( &Cond.mMutex ) == ReleaseMutex( Cond.mMutex )

Condition_Wait( Cond ): 首先釋放互斥量,接著阻塞永久等待事件發生,然後等待互斥量;

Condition_TimedWait( Cond ): 首先釋放互斥量,接著阻塞在一定的時間內等待事件發生,然後等待互斥量;

Condition_Signal( Cond ):因為是手動重設事件,當其被調用時,所有正在等待該事件的線程都會變成可調度狀態;首先需要瞭解SetEvent和PulseEvent的區別,因為是手動重設事件,這對於兩個函數就有區別了,在自動重設事件類型下事件發生後被等待接收後會自動重設為未觸發狀態,具體可以查看《Windows核心編程》第9章的內容,裡面還介紹了SignalObjectAndWait函數的作用呢。

Condition條件變數定義的宏在使用過程中自己是不太理解的,因為調用的時候容易將等待事件和擷取互斥量相互混淆,明明剛釋放了互斥量然後永久等待事件發生時,好不容易等到事件發生了又要擷取互斥量的所有權,所以寫者在每次等待和每次進入以及隨後的退出Condition時都加了相應的Debug輸出,這樣或許能夠容易理解點,因為時間的關係,只能將這事放到後面去啃明白,但是在輸出的過程中確實能發現其起到的作用,比如報告者在無可奉告的情況下等待輸出內容的產生。

 

時間戳記:

估計為了與UNIX統一起來,IPerf在Win32上不是直接調用API使用時間,而是自己封裝了gettimeofday,先通過GetSystemTimeAsFileTime擷取的UTC格式的時間轉換成UNIX新紀元下的時間並通過timeval類型進行返回,在該實現函數中使用了幾個特殊的數字,這在原始碼行上的注釋已經說明清楚,這裡不再講述;

TimeStamp這個類中就只有一個類型為timeval的成員變數,成員函數包括擷取當前的時間,對時間進行相加減,比較兩個時間的先後等,比較容易理解。

時間戳記主要用在資料轉送過程中給每個發送包賦值,表明這個包發送的時間;還有在-i選項在使用的條件下,計算每次需要列印報告的時間,通過比較將要列印報告的時間和最新發送包的時間戳記,決定是否列印這段時間發送的頻寬和發送的資料量以及發送的時間段。

 

作為後台服務運行:

僅用於服務端,並且在作為後台服務運行時,-o filename 選項參數才能起到作用,同樣也是加入他人實現的檔案,稍微看了一下,是通過SCManager的API才建立和執行服務的,這個後面有時間再認真學習,可以考慮自己在後面的某些項目中可以複用。

 

本文暫且就講到這裡,下一篇開始講解線程和角色,也就是結合著線程講解用戶端、服務端、報告者、監聽者的執行過程,暫且僅在TCP模式下,UDP後續再來說明,當然理解了TCP模式下的運行邏輯後,相信UDP模式下也不難理解。

 

IPerf——網路測試載入器介紹與源碼解析(2)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.