標籤:c-store worklist vmware mdcm
背景:
最近去醫院部署裝置,調試PACS系統,遇到了一個奇葩的問題。基本情境是:醫院內部網路情況複雜,多個樓層的診室都安裝了看圖端,都需要訪問頂樓機房的PACS伺服器。起初為了調試關閉了防火牆,並確保各樓層的看圖端與PACS伺服器之間可以ping通,連接埠也順利開放。但是具體部署調試過程中發現“有些樓層可正常進行worklist查詢和Query/Retrieve查詢,而有些樓層只能正常進行worklist查詢,Query/Retrieve查詢後本地並未獲得映像資料”;第二天嘗試後發現“原本正常進行worklist和Query/Retrieve查詢的看圖端,只能正常進行worklist查詢,Query/Retrieve查詢後本地無映像資料,而原本Query/Retrieve查詢失敗的竟然奇蹟的可以下載映像了”。
現場排查:
在看圖端和PACS服務端已經通過ping和talnet指令分別檢測了網路和連接埠的連通性,所以說明網路硬體環境因素基本可以排除。那麼問題多半出在DICOM服務端和看圖端配置方面,最糟糕的是系統內部的bug導致(最不希望看到的就是系統的bug,^_^)。首先拷貝PACS服務端與正常看圖端的記錄檔,與異常的看圖端記錄檔進行對比分析,如所示:
中是正常的看圖端,可以看到在看圖端本地有儲存映像的日誌記錄;而中是異常看圖端的日誌記錄,對比發現PACS服務端響應看圖端的C-Move請求的訊息,即C-Move response,順利到達了看圖端,而看圖端儲存映像資料的資訊並未出現。由於發現C-Move response資訊能夠順利返回,而映像卻不能儲存所以猜測有可能是醫院網路環境中對於影像資料的傳輸進行了限制,因為影像傳輸的資料量較大,但是在跟網管溝通後發現網路方面並未進行任何流量方面的限制。因此第一次排查嘗試失敗。
既然網路環境沒有限制,那麼會是那一部分除了問題呢?為了對問題有一個更全面的把握,決定對醫院的現有看圖端的情況進行統計,希望能夠從中找到線索,所以開始逐樓層進行排查。首先從最底層樓層開始排查,此時確保其他樓層並未有人使用看圖端。逐個排查後發現有部分看圖端依然只能實現worklist查詢,Query/Retrieve查詢仍然失敗,記錄失敗看圖端的IP地址和AETitle,耗費了一整天的時間統計了多個樓層的看圖端串連情況。經過整理髮現大多數Query/Retrieve查詢失敗的看圖端的AETitle竟然有大面積的重合,因此可以斷定大多是由於AETitle的重複而導致的Query/Retrieve查詢失敗。
問題解決:
隨意挑選了AETitle重複的兩台看圖端,通過修改PACS伺服器端和看圖端的AETitle發現問題竟然奇蹟般的解決了。於是通過觀察PACS服務端Dicom節點資料庫檔案對AETitle出現重複的看圖端進行了修改,順利解決了此次部署。
問題模擬:
現場雖然解決了背景中介紹的奇葩問題,但是並未對問題進行深究,例如既然AETitle有重複,那麼為什麼所有看圖端worklist查詢都可以成功,唯獨Query/Retrieve查詢會失敗?既然Query/Retrieve查詢失敗,那麼為什麼PACS服務端的C-Move response響應資訊會出現在看圖端的記錄檔中?為了對問題進行一個全面的分析,找到問題出現的根源。因此回來後決定複原“現場情境”,希望通過分析本地的源碼找到問題的根源。
利用VMWare複原現場
為了在同一台電腦中同時類比出多台看圖端與PACS服務端,我們需要藉助於VMWare虛擬機器工具(最近很火的Docker貌似也可以完成類似的功能,但是由於相關工程是基於Windows開發的,所以估計使用Docker來類比還有一定的困難,如果有大神曾做過類似的類比,還請不吝賜教^_^)。
一、VMWare本機類比結構圖
如所示,利用VMWare WorkStation構建兩個虛擬機器,類比現場中出現重複AETitle的看圖端;本地安裝PACSServer類比醫院的PACS伺服器。基本的類比流程如所示,
1)利用GuestOS-1虛擬機器向HostOS上傳一組資料,因為本地HostOS安裝完PACSServer後其中並未儲存相關資料,所以需要利用GuestOS-1上傳來向PACSServer資料庫寫入一條資料;
2)利用GuestOS-1查詢自己上傳的資料,測試環境PACSServer是否正常運行。經測試證明HostOS中的PACSServer運行正常。
隨後利用GuestOS-1和GuestOS-2來複原醫院現場的情況,
3)GuestOS-1看圖端向伺服器發起worklist查詢服務;
4)GuestOS-1看圖端順利擷取到PACSServer中的患者資訊;
5)GuestOS-2看圖端向伺服器發起worklist查詢服務;
6)GuestOS-2看圖端順利擷取到PACSServer中的患者資訊;
7)GuestOS-1看圖端向伺服器發起Query/Retrieve請求;
8)GuestOS-1看圖端順利獲得C-Move response及映像資訊;
9)GuestOS-2看圖端向伺服器發起Query/Retrieve請求;
10)GuestOS-2看圖端順利獲得C-Move response,但是並未獲得映像資訊;
至此成功複原了當時的現場,為本地調試做好了準備。
二、VMWare虛擬機器GuestOS與HostOS之間網路連接(區域網路)
為了實現上述結構圖中的類比,需要在GuestOS虛擬機器與HostOS之間建立串連。VMWare虛擬機器的網路連接有三種方式:Bridge模式、Host-Only模式、NAT模式。博文(http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/03/15/1985084.html)和博文(http://zhaisx.iteye.com/blog/458671)中對該三種模式有簡單的介紹,大家可以仔細閱讀,此處我選用的是Host-Only模式,HostOS主機的VMware Network Adapter VMnet1的IP地址是192.168.24.1,GuestOS-1的IP地址是192.168.24.100,GuestOS-2的IP地址是192.168.24.200.
Dicom Network源碼分析(基於mDCM)
此處的DicomViewer看圖端和PACSServer服務端採用的是C#編寫的mDCM開源庫。為瞭解決上述問題,此處對mDCM開源庫中Dicom Network的相關類進行分析,對mDCM中DICOM網路服務的實現流程有一個宏觀的認識,期望能夠快速找到上述問題的根源。
從Github上下載mDCM的源碼,利用VS開啟(如)。找到mDCM中關於DICOM網路服務的檔案夾Network,可以看到mDCM按照Client和Server將DICOM網路服務的實作類別分成了兩部分。
中的各個類之間的繼承關係如下所示,
此處通過對PACSServer服務端的實現來剖析一下mDCM的相關類,對於用戶端分支的相關分析此處就不做介紹了,用戶端的流程比服務端要簡單,主要是一個主動串連及被動接收服務端應答的過程,相應的處理函數也比較少,有興趣的同學可自己瀏覽mDCM源碼。
DcmNetworkBase |
是mDCM實現DICOM網路服務的基類,類中給出了基類網路服務的基礎函數, 1)可重載的各類請求和應答的響應函數,如OnReceiveEchoRequest/OnReceiveEchoResponse、OnReceiveCMoveRequest/OnReceiveCMoveResponse等等。作為基類,各響應函數內部並未真正實現相應的操作,只是簡單的發送終止應答,即調用SendAbort函數。 2)不可重載的,可派生的發送各種請求和應答的函數,如SendEchoRequest/SendEchoResponse、SendCMoveRequest/SendCMoveResponse等等。該類函數按照DICOM網路服務協議的要求,封裝好了相應的發送操作,派生後可自由使用。 3)私人的,限定關鍵流程的函數,如Process、ProcessNetPDU、ProcessPDataTF、ProcessDimse。這四個函數表明了DICOM服務中資訊流的流向,使用者不可修改該流程,但是可通過重載相應的請求和應答函數向該流程中添加自己的操作。 4)私人的,限定底層網路操作流程的函數,如Connect。使用者可通過重載OnInitializeNetwork函數來向串連流程中添加自己的操作。 |
CStoreService |
CStoreService是服務端用來相應C-STORE 請求的類,即C-STORE-SCP類,派生自DcmNetworkBase基類,並對基類中關於C-STORE請求和C-ECHO請求進行了定製。 重載實現的函數有: 1)OnReceiveAssociateRequest 2)OnReceiveCStoreRequest,函數中調用了OnReceiveCStore委託,通過綁定自己的函數可對CStore請求進行定製化操作。例如資料庫的寫入等。 3)OnReceiveEchoRequest 4)OnReceiveDimseBegin 5)OnReceiveDimseProgress 後兩個函數可以在DcmNetworkBase基類對DIMSE訊息進行處理之前添加自己的操作,兩個函數中調用的是OnCStoreRequestBegin和OnCStoreRequestProgress兩個委託,例如可進行相關日誌的寫入操作。 |
CEchoService |
該類是一個串連測試類別,比較簡單。重載了OnReceiveAssociationRequest和OnReceiveEchoRequest兩個函數。 |
DcmServer<T> where T:DcmSeriveBase |
該類是我們以後編寫PACSServer服務端具體用到了泛型類,該類包含派生自DcmServiceBase的服務類成員,然後通過制定基本的串連流程來實現PACSServer服務端。關於流程的相關函數有, 1)共有的,可訪問的啟動、關閉和連接埠等相關操作函數,如AddPort、Start、Stop等 2)私人的,不可更改的核心流程式控制制函數,ServerProc。該函數選用Select模式來接收用戶端的響應,然後針對獲得的用戶端socket對象調用派生自DcmServiceBae的服務類來實現PACSServer的功能,具體PACSServer提供的功能由T:DcmServiceBase類來決定。 |
從上述表格中我們對mDCM實現DICOM網路服務的流程有了一個基本的把握,下面從真實的PACSServer實現代碼入手,給出具體的相關DICOM網路服務流的流向,如所示:
中ServerProc到Process到ProcessNextPDU到ProcessPDataTF到ProcessDimse的流向就是mDCM對DICOM網路服務實現的控制流程,並且上述四步控制,即
ServerProc、Process、ProcessNextPDU、ProcessPDataTF、ProcessDimse,都是表格中所提到的各個類中的私人函數,言外之意就是我們不能夠隨意更改整體處理流程,但是對於各處理部分相應的處理函數可自由定製。 通過上述的剖析我們對mDCM的具體實現有了一個深刻的瞭解,那麼接下來就是分析問題根源的時候了。對於Query/Retrieve請求,發出的是C-MOVE Request,那麼從流向中我們可以定位到PacsSCPImpl類中的OnReceiveCMoveRequest函數內部,插入斷點,單步調試。具體流程為:1)啟動PACSServer進入偵錯模式;2)利用GuestOS-1虛擬機器中的DicomViewer發起Query/Retrieve查詢;3)PACSServer進入到OnReceiveCMoveRequest函數內部;按照同樣的流程啟動GuestOS-2的看圖端發起Query/Retrieve請求,通過對比觀察兩次調試時刻的成員變數和局部變數發現,由於GuestOS-1和GuestOS-2中的AETitle相同,PACSServer服務端內部在資料庫檢索時刻搜尋到
第一個對應的AETitle對應的用戶端IP地址後就退出了,因此對於GuestOS-1和GuestOS-2中的AETitle相同的情況,永遠是在伺服器資料庫中順序靠前的那一個看圖端可以順利完成Query/Retrieve查詢請求。通過修改PACSServer服務端資料庫中GuestOS-1和GuestOS-2的順序得到了驗證。那麼還有另外一個問題就是:失敗的GuestOS-2中的DicomViewer記錄檔中為什麼會接收到C-MOVE Response資訊呢?再次按照上述方法進入到單步偵錯模式,發現在相應用戶端發起的Query/Retrieve請求時,對於應答的發送使用的是DcmNetworkBase基類中的SendCMoveResponse函數,該函數對於C-MOVE response資訊的發送是
根據PACSServer服務端監聽通訊端接收到的用戶端通訊端來完成的,因此
並未通過查詢服務端資料庫中的AETitle來擷取客戶機的IP地址。 至此對於此次奇葩問題有了一個完美的解答,最後總結一下。雖然mDCM庫中對於資訊的發送有的是通過查詢資料庫來擷取目的地IP地址,有的是直接利用客戶機的通訊端來擷取IP地址,按理來說如果是直接利用通訊端中的IP地址來發送訊息(如上述的SendCMoveResponse)看圖端中的AETitle是可以相同的,但是隨著醫院資訊系統的擴充,看圖端數量的增加,建議還是按照DICOM3.0標準來設定不同的AETitle以區分網路中的各終端裝置。如果不是此次現場部署的醫院看圖端足夠多(原本的設計是根據IP地址的最後一位添加“SCU_”首碼來命名各個看圖端,沒想到的是醫院每個樓層都有上百台看圖端,因此導致只以IP地址最後一部分為尾碼的AETitle命名方式出現了重複)也不會發現PACSServer服務端程式中的問題。備忘:1)VMWare虛擬機器安裝Win7出現“GCDROM not loaded”錯誤
搜尋了網路上的部分資料,最後從WinPE啟動進入後,對虛擬機器的硬碟進行格式化和分區,然後利用WinPE中的安裝工具成功在VMWare虛擬機器中安裝Win7作業系統。
2)後續博文介紹
Dicom中的MPPS服務介紹
C#的非同步編程模式在fo-dicom中的應用
VMWare三種網路連接模式的實際測試
[email protected]
時間:2014-09-28
DICOM醫學影像處理:AETitle在C-FIND和C-MOVE請求中的設定問題