最近去醫(yī)院部署設(shè)備,調(diào)試PACS系統(tǒng),遇到了一個(gè)奇葩的問題。基本場(chǎng)景是:醫(yī)院內(nèi)部網(wǎng)絡(luò)情況復(fù)雜,多個(gè)樓層的診室都安裝了看圖端,都需要訪問頂樓機(jī)房的PACS服務(wù)器。起初為了調(diào)試關(guān)閉了防火墻,并確保各樓層的看圖端與PACS服務(wù)器之間可以ping通,端口也順利開放。但是具體部署調(diào)試過(guò)程中發(fā)現(xiàn)“有些樓層可正常進(jìn)行worklist查詢和Query/Retrieve查詢,而有些樓層只能正常進(jìn)行worklist查詢,Query/Retrieve查詢后本地并未獲得圖像數(shù)據(jù)”;第二天嘗試后發(fā)現(xiàn)“原本正常進(jìn)行worklist和Query/Retrieve查詢的看圖端,只能正常進(jìn)行worklist查詢,Query/Retrieve查詢后本地?zé)o圖像數(shù)據(jù),而原本Query/Retrieve查詢失敗的竟然奇跡的可以下載圖像了”。
在看圖端和PACS服務(wù)端已經(jīng)通過(guò)ping和talnet指令分別檢測(cè)了網(wǎng)絡(luò)和端口的連通性,所以說(shuō)明網(wǎng)絡(luò)硬件環(huán)境因素基本可以排除。那么問題多半出在DICOM服務(wù)端和看圖端配置方面,最糟糕的是系統(tǒng)內(nèi)部的bug導(dǎo)致(最不希望看到的就是系統(tǒng)的bug,^_^)。首先拷貝PACS服務(wù)端與正常看圖端的日志文件,與異常的看圖端日志文件進(jìn)行對(duì)比分析,如下圖所示:
上圖中是正常的看圖端,可以看到在看圖端本地有保存圖像的日志記錄;而下圖中是異常看圖端的日志記錄,對(duì)比上圖發(fā)現(xiàn)PACS服務(wù)端響應(yīng)看圖端的C-Move請(qǐng)求的消息,即C-Move response,順利到達(dá)了看圖端,而看圖端保存圖像數(shù)據(jù)的信息并未出現(xiàn)。由于發(fā)現(xiàn)C-Move response信息能夠順利返回,而圖像卻不能保存所以猜測(cè)有可能是醫(yī)院網(wǎng)絡(luò)環(huán)境中對(duì)于影像數(shù)據(jù)的傳輸進(jìn)行了限制,因?yàn)橛跋駛鬏數(shù)臄?shù)據(jù)量較大,但是在跟網(wǎng)管溝通后發(fā)現(xiàn)網(wǎng)絡(luò)方面并未進(jìn)行任何流量方面的限制。因此第一次排查嘗試失敗。
既然網(wǎng)絡(luò)環(huán)境沒有限制,那么會(huì)是哪一部分出了問題呢?為了對(duì)問題有一個(gè)更全面的把握,決定對(duì)醫(yī)院的現(xiàn)有看圖端的情況進(jìn)行統(tǒng)計(jì),希望能夠從中找到線索,所以開始逐樓層進(jìn)行排查。首先從最底層樓層開始排查,此時(shí)確保其他樓層并未有人使用看圖端。逐個(gè)排查后發(fā)現(xiàn)有部分看圖端依然只能實(shí)現(xiàn)worklist查詢,Query/Retrieve查詢?nèi)匀皇。涗浭】磮D端的IP地址和AETitle,耗費(fèi)了一整天的時(shí)間統(tǒng)計(jì)了多個(gè)樓層的看圖端連接情況。經(jīng)過(guò)整理發(fā)現(xiàn)大多數(shù)Query/Retrieve查詢失敗的看圖端的AETitle竟然有大面積的重合,因此可以斷定大多是由于AETitle的重復(fù)而導(dǎo)致的Query/Retrieve查詢失敗。
隨意挑選了AETitle重復(fù)的兩臺(tái)看圖端,通過(guò)修改PACS服務(wù)器端和看圖端的AETitle發(fā)現(xiàn)問題竟然奇跡般的解決了。于是通過(guò)觀察PACS服務(wù)端Dicom節(jié)點(diǎn)數(shù)據(jù)庫(kù)文件對(duì)AETitle出現(xiàn)重復(fù)的看圖端進(jìn)行了修改,順利解決了此次部署中出現(xiàn)的奇葩問題。
現(xiàn)場(chǎng)雖然解決了背景中介紹的奇葩問題,但是并未對(duì)問題進(jìn)行深究,例如既然AETitle有重復(fù),那么為什么所有看圖端worklist查詢都可以成功,唯獨(dú)Query/Retrieve查詢會(huì)失敗?既然Query/Retrieve查詢失敗,那么為什么PACS服務(wù)端的C-Move response響應(yīng)信息會(huì)出現(xiàn)在看圖端的日志文件中?為了對(duì)問題進(jìn)行一個(gè)全面的分析,找到問題出現(xiàn)的根源。因此回來(lái)后決定復(fù)原“現(xiàn)場(chǎng)場(chǎng)景”,希望通過(guò)分析本地的源碼找到問題的根源。
為了在同一臺(tái)電腦中同時(shí)模擬出多臺(tái)看圖端與PACS服務(wù)端,我們需要借助于VMWare虛擬機(jī)工具(最近很火的Docker貌似也可以完成類似的功能,但是由于相關(guān)工程是基于Windows開發(fā)的,所以估計(jì)使用Docker來(lái)模擬還有一定的困難,如果有大神曾做過(guò)類似的模擬,還請(qǐng)不吝賜教^_^)。
如上圖所示,利用VMWare WorkStation構(gòu)建兩個(gè)虛擬機(jī),模擬現(xiàn)場(chǎng)中出現(xiàn)重復(fù)AETitle的看圖端;本地安裝PACSServer模擬醫(yī)院的PACS服務(wù)器。基本的模擬流程如上圖所示,
1)利用GuestOS-1虛擬機(jī)向HostOS上傳一組數(shù)據(jù),因?yàn)楸镜豀ostOS安裝完P(guān)ACSServer后其中并未存儲(chǔ)相關(guān)數(shù)據(jù),所以需要利用GuestOS-1上傳來(lái)向PACSServer數(shù)據(jù)庫(kù)寫入一條數(shù)據(jù);
2)利用GuestOS-1查詢自己上傳的數(shù)據(jù),測(cè)試環(huán)境PACSServer是否正常運(yùn)行。經(jīng)測(cè)試證明HostOS中的PACSServer運(yùn)行正常。
隨后利用GuestOS-1和GuestOS-2來(lái)復(fù)原醫(yī)院現(xiàn)場(chǎng)的情況,
3)GuestOS-1看圖端向服務(wù)器發(fā)起worklist查詢服務(wù);
4)GuestOS-1看圖端順利獲取到PACSServer中的患者信息;
5)GuestOS-2看圖端向服務(wù)器發(fā)起worklist查詢服務(wù);
6)GuestOS-2看圖端順利獲取到PACSServer中的患者信息;
7)GuestOS-1看圖端向服務(wù)器發(fā)起Query/Retrieve請(qǐng)求;
8)GuestOS-1看圖端順利獲得C-Move response及圖像信息;
9)GuestOS-2看圖端向服務(wù)器發(fā)起Query/Retrieve請(qǐng)求;
10)GuestOS-2看圖端順利獲得C-Move response,但是并未獲得圖像信息;
至此成功復(fù)原了當(dāng)時(shí)的現(xiàn)場(chǎng),為本地調(diào)試做好了準(zhǔn)備。
為了實(shí)現(xiàn)上述結(jié)構(gòu)圖中的模擬,需要在GuestOS虛擬機(jī)與HostOS之間建立連接。VMWare虛擬機(jī)的網(wǎng)絡(luò)連接有三種方式:Bridge模式、Host-Only模式、NAT模式。博文(http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/03/15/1985084.html)和博文(http://zhaisx.iteye.com/blog/458671)中對(duì)該三種模式有簡(jiǎn)單的介紹,大家可以仔細(xì)閱讀,此處我選用的是Host-Only模式,HostOS主機(jī)的VMware Network Adapter VMnet1的IP地址是192.168.24.1,GuestOS-1的IP地址是192.168.24.100,GuestOS-2的IP地址是192.168.24.200.
此處的DicomViewer看圖端和PACSServer服務(wù)端采用的是C#編寫的mDCM開源庫(kù)。為了解決上述問題,此處對(duì)mDCM開源庫(kù)中Dicom Network的相關(guān)類進(jìn)行分析,對(duì)mDCM中DICOM網(wǎng)絡(luò)服務(wù)的實(shí)現(xiàn)流程有一個(gè)宏觀的認(rèn)識(shí),期望能夠快速找到上述問題的根源。【注】:專欄的前幾篇博文中提到過(guò)mDCM與fo-dicom、DCMTK的關(guān)系,有興趣的可以進(jìn)入我的專欄閱讀一下。
從Github上下載mDCM的源碼,利用VS打開(如下圖)。找到mDCM中關(guān)于DICOM網(wǎng)絡(luò)服務(wù)的文件夾Network,可以看到mDCM按照Client和Server將DICOM網(wǎng)絡(luò)服務(wù)的實(shí)現(xiàn)類分成了兩部分。
上圖中的各個(gè)類之間的繼承關(guān)系如下所示,
此處通過(guò)對(duì)PACSServer服務(wù)端的實(shí)現(xiàn)來(lái)剖析一下mDCM的相關(guān)類,對(duì)于客戶端分支的相關(guān)分析此處就不做介紹了,客戶端的流程比服務(wù)端要簡(jiǎn)單,主要是一個(gè)主動(dòng)連接及被動(dòng)接收服務(wù)端應(yīng)答的過(guò)程,相應(yīng)的處理函數(shù)也比較少,有興趣的同學(xué)可自己瀏覽mDCM源碼。
DcmNetworkBase |
DcmNetworkBase是mDCM實(shí)現(xiàn)DICOM網(wǎng)路服務(wù)的基類,類中給出了基類網(wǎng)絡(luò)服務(wù)的基礎(chǔ)函數(shù),主要由以下幾類: 1)可重載的各類請(qǐng)求和應(yīng)答的響應(yīng)函數(shù),如OnReceiveEchoRequest/OnReceiveEchoResponse、OnReceiveCMoveRequest/OnReceiveCMoveResponse等等。作為基類,各響應(yīng)函數(shù)內(nèi)部并未真正實(shí)現(xiàn)相應(yīng)的操作,只是簡(jiǎn)單的發(fā)送終止應(yīng)答,即調(diào)用SendAbort函數(shù)。 2)不可重載的,可派生的發(fā)送各種請(qǐng)求和應(yīng)答的函數(shù),如SendEchoRequest/SendEchoResponse、SendCMoveRequest/SendCMoveResponse等等。該類函數(shù)按照DICOM網(wǎng)絡(luò)服務(wù)協(xié)議的要求,封裝好了相應(yīng)的發(fā)送操作,派生后可自由使用。 3)私有的,限定關(guān)鍵流程的函數(shù),如Process、ProcessNetPDU、ProcessPDataTF、ProcessDimse。這四個(gè)函數(shù)表明了DICOM服務(wù)中信息流的流向,用戶不可修改該流程,但是可通過(guò)重載相應(yīng)的請(qǐng)求和應(yīng)答函數(shù)向該流程中添加自己的操作。 4)私有的,限定底層網(wǎng)絡(luò)操作流程的函數(shù),如Connect。用戶可通過(guò)重載OnInitializeNetwork函數(shù)來(lái)向連接流程中添加自己的操作。 |
CStoreService |
CStoreService是服務(wù)端用來(lái)相應(yīng)C-STORE 請(qǐng)求的類,即C-STORE-SCP類,派生自DcmNetworkBase基類,并對(duì)基類中關(guān)于C-STORE請(qǐng)求和C-ECHO請(qǐng)求進(jìn)行了定制。 重載實(shí)現(xiàn)的函數(shù)有: 1)OnReceiveAssociateRequest 2)OnReceiveCStoreRequest,函數(shù)中調(diào)用了OnReceiveCStore委托,通過(guò)綁定自己的函數(shù)可對(duì)CStore請(qǐng)求進(jìn)行定制化操作。例如數(shù)據(jù)庫(kù)的寫入等。 3)OnReceiveEchoRequest 4)OnReceiveDimseBegin 5)OnReceiveDimseProgress 后兩個(gè)函數(shù)可以在DcmNetworkBase基類對(duì)DIMSE消息進(jìn)行處理之前添加自己的操作,兩個(gè)函數(shù)中調(diào)用的是OnCStoreRequestBegin和OnCStoreRequestProgress兩個(gè)委托,例如可進(jìn)行相關(guān)日志的寫入操作。 |
CEchoService |
該類是一個(gè)連接測(cè)試類,比較簡(jiǎn)單。重載了OnReceiveAssociationRequest和OnReceiveEchoRequest兩個(gè)函數(shù)。 |
DcmServer<T> where T:DcmSeriveBase |
該類是我們以后編寫PACSServer服務(wù)端具體用到了泛型類,該類包含派生自DcmServiceBase的服務(wù)類成員,然后通過(guò)制定基本的連接流程來(lái)實(shí)現(xiàn)PACSServer服務(wù)端。關(guān)于流程的相關(guān)函數(shù)有, 1)共有的,可訪問的啟動(dòng)、關(guān)閉和端口等相關(guān)操作函數(shù),如AddPort、Start、Stop等 2)私有的,不可更改的核心流程控制函數(shù),ServerProc。該函數(shù)選用Select模式來(lái)接收客戶端的響應(yīng),然后針對(duì)獲得的客戶端socket對(duì)象調(diào)用派生自DcmServiceBae的服務(wù)類來(lái)實(shí)現(xiàn)PACSServer的功能,具體PACSServer提供的功能由T:DcmServiceBase類來(lái)決定。 |
搜索了網(wǎng)絡(luò)上的部分資料,最后從WinPE啟動(dòng)進(jìn)入后,對(duì)虛擬機(jī)的硬盤進(jìn)行格式化和分區(qū),然后利用WinPE中的安裝工具成功在VMWare虛擬機(jī)中安裝Win7操作系統(tǒng)。
Dicom中的MPPS服務(wù)介紹
C#的異步編程模式在fo-dicom中的應(yīng)用
VMWare三種網(wǎng)絡(luò)連接模式的實(shí)際測(cè)試
作者:zssure@163.com
時(shí)間:2014-09-28