DICOM醫學圖形處理:storescp.exe與storescu.exe源碼剖析,學習C-STORE請求(續)

來源:互聯網
上載者:User

標籤:c-store   dicom   dcmscp   c++   dcmtk   

背景:

        上一篇博文中,在對storescp工具源檔案storescp.cc和DcmSCP類的源檔案scp.cc進行剖析後,得出了兩者都可以實現響應C-ECHO和C-STORE(需要對DcmSCP類進行擴充)請求的功能。但是在對DcmSCP類進行擴充,期望類比實現自己的storescp.exe工具時遇到了問題,用戶端提示服務中斷連結,而服務端顯示儲存失敗,如所示。此次博文通過排除該問題再一次對storescp.cc和scp.cc進行對比,主要從Presentation Context、AbstractSyntax、TransferSyntax等細節出發,認真學習DICOM通訊服務。

問題排除:1)對比分析storescp.exe工具包與自訂工具包的調試資訊

        為了排除storescu.exe用戶端的問題,大致確定問題出現的範圍,決定再一次用storescp.exe作為用戶端,使用storescu.exe對其發送C-STORE請求,查看storescu.exe用戶端的調試資訊。與我們的自訂工具服務端的調試資訊進行對比。


        對比中的調試資訊,其中紅色部分END A-ASSOCIATE-AC表示的是服務端已經順利的與用戶端完成了握手,即網路已經順利響應了用戶端的串連。藍色部分表示用戶端發送的C-STORE-RQ請求也已經順利的到達了服務端,唯一不同的就是黃色圓圈標記的部分,說明在服務端接收到C-STORE-RQ請求後對其處理有問題。而我們自己封裝的ZSDcmStoreSCP類對於C-STORE-RQ的處理函數是直接拷貝的storescp.exe工具內的storeSCP和storeSCPCallback函數。因此大致可以確定問題可能出現的範圍。

2)單步調試

        在handleIncomingCommand函數內部調用storeSCP指令處插入斷點,進入單步調試狀態。利用VS2012提供的新的調試工具“並行堆棧”,找到了第一個返回狀態cond.bad()為true的地方,即函數ASC_findAcceptedPresentationContext,如所示:

        繼續單步調試,進入到ASC_findAcceptedPresentationContext函數內部,發現真正出現錯誤的地方是findPresentationContextID,該函數的參數presentationContextID始終為零。

猜測:可能是presentationContextID參數在傳遞過程中的某一環節出錯了,導致程式失敗。為了驗證我們的想法,開啟storescp.exe工程,進入偵錯模式,查看參數的數值情況,如所示,storescp.exe工具包中presentationContextID參數的值為41。因此證明了我們在presentationContextID參數傳遞的過程中發生了錯誤。

3)參數傳遞流向

        為了確定具體傳遞過程中的錯誤環節,我們採取回溯的方式,通過回溯findPresentationContextID函數中presentationContextID參數的來源來確定問題出現的具體位置。


(註:為了方便講圖片旋轉了90度,勞煩大家歪著脖子將就著看一下下吧哈)

        從中可以看出T_ASC_PresentationContextID參數最終的來源是我們重載DcmSCP基類的handleIncomingCommand函數,因此與storescp.exe中的是實現對比,仔細查看該部分的代碼,發現了一個重大問題,原來我們在將storescp.exe工具中的processCommands函數內容拆解到handleIncomingCommand函數內部時,將多餘的DIMSE_receiveCommand函數注釋掉的同時,遺漏了注釋掉T_ASC_Association局部變數,使得原本應該通過DIMSE_receiveCommand函數擷取的presID變數一直被局部變數覆蓋為0——至此問題找到了。

        那麼由於注釋掉了多餘的DIMSE_receiveCommand函數,我們從何處來擷取presID參數呢。查看一下handleIncomingCommand函數的頭髮現函數參數中也沒有出現T_ASC_PresentationContextID類型的參數。但是對比scp.cc原本處理C-ECHO請求的函數handleECHORequest我們發現,scp.cc類中將presID的值儲存在了DcmPresentationContextInfo類型的presInfo變數中。因此我們修改storeSCP的調用,將presInfo.presentationContextID傳遞進入作為presID的初值。

        修改完成後,再次調試發現程式運行正常,用戶端順利收到了服務端反饋回來的DIMSE Message,並且在服務端的目錄下也看到了storescu.exe傳遞過來的dcm檔案(當然在storeSCP函數內部根據時間等資訊對檔案進行了重新命名)。


至此上一博文中自類比storescp.exe工具包的問題已經順利解決,利用我們自己封裝的ZSDcmStoreSCP類可以簡單地實現storescp.exe工具包的功能。

總結分析:

        此次調試排除錯誤的過程中發現,在組合移接不同檔案的代碼時要格外的注意細節部分。順便藉著此次傳遞丟失T_ASC_Association型別參數的問題,我們詳細的分析一下傳遞失敗的T_ASC_Associaton型別參數的作用,為什麼簡單的一個參數傳遞失敗,就會導致C-STORE功能失效?

1)Presentation Context、AbstractSyntax、TransferSyntax細節學習

        在上一篇博文中我們摘錄了DICOM3.0標準中關於Presentation Context、AbstractSyntax、TransferSyntax幾個名詞的解釋,通俗一點來講就是說Presentation Context代表的是兩個應用實體(AE=Applicaiton Entity)互動的環境(通常叫做上下文),它包含後面的AbstractSyntax和TransferSyntax名詞。AbstractSyntax與TransferSyntax比較容易混淆就是因為英文單詞中都包含了Syntax,其實兩者完全是不同的概念,AbstractSyntax關注的是上層資訊,即兩個互動的AE之間 進行的是何種互動,也就是標準中所說的服務物件對(SOP)的類型,通過查看dcuid.h檔案可知,AbstractSyntax有Store、Query/Retrive、Worklist等類型,例如Store類型的UID_CTImageStorage 、Query/Retrive類型的UID_FINDPatientRootQueryRetrieveInformationModel、Worklist類型的UID_FINDModalityWorklistInformationModel等等。這幾個是我們在C-ECHO、C-STORE、C-FIND服務中常用到的幾種;而TransferSyntax關注的是資訊傳輸互動時的編碼規則,是Explicit還是Implicit,是LittleEndian還是BigEndian,常見的有UID_LittleEndianImplicitTransferSyntax、UID_LittleEndianExplicitTransferSyntax等等,具體的可以自行查看dcuid.h檔案。而上面傳遞丟失的presID參數就是包括了這兩種最重要的互動資訊。因此會導致整個C-STORE服務失敗。

2)storescp.cc與scp.cc整體再對比

        那麼storescp.exe工具包和DcmScp類又是在什麼時刻?什麼位置來設定這些參數的呢?下面我們就再一次對比分析一下兩種工具的實現流程(細節可參照上一篇博文DICOM醫學影像處理:storescp.exe與storescu.exe源碼剖析,學習C-STORE請求)。

2.1 scp.cc源碼檔案

        藉助上一篇博文的圖片來分析一下DcmSCP類中對於Presentation Context(即AbstractSyntax和TransferSyntax)的具體操作。


        中給出了DcmSCP類中設定Presentation Context上下文環境的具體位置和使用的函數。

2.2 storescp.exe源碼檔案

        想必storescp.exe工具包中的設定流程也基本是相似的,接下來我們同樣藉助上一篇博文的圖來分析一下。


        對比兩個圖片我們可以發現DcmSCP和storescp.exe都是在處理真正的DIMSE訊息之前對串連的Presentation Context上下文進行配置,至於這麼多UID(無論是AbstractSyntax還是TransferSyntax都是在dcuid.h檔案中用統一的UID來定義的)儲存到哪裡了呢?結合上一篇博文的分析,我們知道外部迴圈開始後主要的核心函數都有一個T_ASC_Association類型的參數assoc(storescp.exe中)或m_assoc(DcmSCP類中),查看一下T_ASC_Association類型的定義,並逐級開啟,可以發現正如我們預料中的一樣,該變數中儲存了串連的內容相關的所有UID,如所示:


        至此我們對於DcmSCP類和storescp.exe工具的源碼的剖析總算告一段落了,希望大家能夠對DICOM的網路通訊服務有一個更深刻的認識。

3)對新版DCMTK中DcmSCP和DcmStoreSCP實現的初步猜想

        通過此次使用DcmSCP類的工程發現,該類的設計有些欠妥,開放的介面不夠合理,無法輕鬆的實現擴充來響應C-STORE等其他請求。猜想新版的DCMTK肯定會進行修改,通過查看dcmtk3.6.1的官方說明,發現新版的dcmtk開源庫中的確對DcmSCP和DcmSCU基類進行了大的修改,開放了眾多新的介面(如)方便使用者進行擴充,另外新版的庫中直接給出了封裝好的DcmStoreSCP和DcmStoreSCU類,所以大家就不要使用我給出的代碼ZSDcmStoreSCP類啦,僅供測試使用,具體運用是還是趕緊安裝最新版的dcmtk開源庫吧。

執行個體工程代碼下載:
1)CSDN資源下載:

串連:http://download.csdn.net/detail/zssureqh/7870789,需要1個積分奧。

2)Github免費下載

串連:https://github.com/zssure-thu/CSDN

後續專欄博文預告:

1)dcmtk3.6.0的DcmSCP與dcmtk3.6.1的DcmSCP分析,以及dcmtk3.6.1的DcmStoreSCP和DcmStoreSCU的使用

2)Dcmtk與fo-dicom儲存檔案的不同設計模式:單線程VS多線程

3)wlmscpfs.exe與findscu.exe的源碼剖析:學習C-FIND請求


[email protected]

時間:2014-09-13


DICOM醫學圖形處理:storescp.exe與storescu.exe源碼剖析,學習C-STORE請求(續)

相關文章

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.