引言
??前篇介紹了 DICOM C-Get 消息服務体箕,本文結合開源 DICOM 庫 fo-dicom 詳細介紹一下 C-Move 服務。
C-Move 消息服務
??C-Move 服務可以用來獲取影像和轉存影像,用于一個 DIMSE-service-user 在同等的 DIMSE-service-user 上查詢復合 SOP 實例的屬性滿足查詢條件給出的一組屬性的復合 SOP 實例,并取回這些符合條件的復合 SOP 實例眨唬,同時在這個過程中將觸發(fā)一個或多個 C-STORE 子操作過程,所有的 C-STORE 子操作觸發(fā)在另外一個單獨的 Association 連接中姥闪。從這里可以看出 C-Move 和 C-Get 服務很類似,唯一的區(qū)別在于 C-Move 所觸發(fā)的 C-Store 子操作在另外一個單獨的 Association 連接中砌烁,而 C-Get 所觸發(fā)的 C-Store 子操作是和 C-Get 在同一個 Association 連接中筐喳。
??DICOM 標準中是這樣定義的:
The C-MOVE service is used by a DIMSE-service-user to match a set of Attributes against the Attributes of a set of composite SOP Instances maintained by a peer DIMSE-service-user, and retrieve all composite SOP Instances that match. It triggers one or more C-STORE sub-operations on a separate Association. It is a confirmed service.
??所以C-Move 可以支持兩方通信,也可以支持三方通信函喉。
??C-Move 服務兩方通信流程圖如下:
C-Move SCU
??開源 DICOM 庫 fo-dicom 已經封裝好了 C-Move Request避归,具體代碼可以在 GitHub 上查看 DicomCMoveRequest.cs,我們只需要通過如下代碼就能夠構造一個簡單的 C-Move SCU管呵,需要引用命名空間【Dicom.Network】梳毙。
using Dicom.Network;
var client = new DicomClient();
var request = new DicomCMoveRequest({C-Store SCP AE Title}, {StudyInstanceUID});
client.AddRequest(request);
client.Send({C-Move SCP IP}, {C-Move SCP Port}, false, {C-Move SCU AE Title}, {C-Move SCP AE Title});
- C-Store SCP AE Title:影像歸檔目的地的 AE Title,之所以這樣寫撇寞,是因為 C-Move 既可以是兩方通信,也可以是三方通信堂氯,如果是兩方通信蔑担,那么 C-Move SCU 同時需要提供 C-Store SCP 的功能,這里就可以寫 C-Move SCU 的 AE Title咽白;如果是三方通信啤握,那么這個影像歸檔的目的地之需要提供 C-Store SCP 的功能,所以這里的參數就要寫C-Store SCP 的 AE Title晶框;
- StudyInstanceUID:檢查唯一標識排抬;
- C-Move SCP IP:C-Move 服務端的 IP 地址或機器名;
- C-Move SCP Port:C-Move 服務端的端口授段;
- C-Move SCU AE Title:C-Move 客戶端應用實體的名稱蹲蒲;
- C-Move SCP AE Title:C-Move 服務端應用實體的名稱;
??如果我們需要獲取 C-Store 過程中的一些信息侵贵,例如成功數量届搁、失敗數量和待 C-Store 操作數量這些,可以加上下面的代碼:
request.OnResponseReceived += (DicomCMoveRequest requ, DicomCMoveResponse response) =>
{
if (response.Status.State == DicomState.Pending)
{
Console.WriteLine("Sending is in progress. please wait: " + response.Remaining + " SOP instances need to do C-Store options");
}
else if (response.Status.State == DicomState.Success)
{
Console.WriteLine("Sending successfully finished");
}
else if (response.Status.State == DicomState.Failure)
{
Console.WriteLine("Error sending datasets: " + response.Status.Description);
}
Console.WriteLine(response.Status);
};
C-Move SCP
??C-Move SCP 可以通過派生 DicomService 服務類來實現(xiàn) Dicom 服務的基本框架,然后實現(xiàn) IDicomServiceProvider 和 IDicomCMoveProvider 接口來實現(xiàn)卡睦,部分代碼可以參考這里宴胧,核心部分是實現(xiàn) OnCMoveRequest 方法。
C-Move 過程分析
??由于包的數據量比較大表锻,所以和之前分析 C-Get 服務一樣恕齐,我過濾掉不能被解碼成 DICOM 協(xié)議的包,只分析能被解碼成 DICOM 協(xié)議的包瞬逊,先看第一部分:
紅色框內的兩行是兩個 AE 建立 association 的過程:
- C-Move SCU(10.3.13.202)向 C-Move SCP(10.3.2.209) 發(fā)送 A-ASSOCIATE 請求显歧;
- C-Move SCP(10.3.2.209)響應 C-Move SCU(10.3.13.202)的 A-ASSOCIATE 請求,然后兩個 AE 就建立了一個 association码耐;
藍色框中的數據包是 C-Move SCU(10.3.13.202)向 C-Move SCP(10.3.2.209) 發(fā)送 C-Move 請求追迟,通過查看包的詳細內容可以看到我們查詢的 level 是檢查這一級,參數是一個 StudyInstanceUID骚腥,C-Move 請求發(fā)送完畢后接著就是下圖的數據包了:
紅色框內的兩行是兩個 AE 建立 association 的過程敦间,這個是 C-Move 請求觸發(fā)的 C-Store 子操作所建立的 association 連接:
- C-Move SCP(C-Store SCU,10.3.2.209)向 C-Move SCU(C-Store SCP束铭,10.3.13.202) 發(fā)送 A-ASSOCIATE 請求廓块;
- C-Move SCU(C-Store SCP,10.3.13.202)響應 C-Move SCP(C-Store SCU契沫,10.3.2.209)的 A-ASSOCIATE 請求带猴,然后兩個 AE 就建立了一個 association,這個 association 用于 C-Store 請求交互懈万;
后續(xù)的藍色框就是 C-Move SCP(C-Store SCU拴清,10.3.2.209)向 C-Move SCU(C-Store SCP,10.3.13.202)發(fā)送 C-Store 請求会通,這里一個 SOP 實例對象會被拆分成多個數據包發(fā)送口予,詳見下圖:
從上圖可以看出單個 SOP 實例對象所有的 C-Store 數據包除了一個都說明了在收到 Frame 12194 后進行重組,同時單個 SOP 實例對象的最后一個數據包是一個畸形數據包涕侈,這個數據包重組之前收到的數據包后將 SOP 實例對象的 Tag 值按照 DICOM 標準都可以解析出來了沪停。
接著看上圖,在一個 SOP 實例對象 C-Store 歸檔完后裳涛,C-Move SCU(C-Store SCP木张,10.3.13.202)會向 C-Move SCP(C-Store SCU,10.3.2.209)發(fā)送一個 C-Store 響應端三,會返回 C-Move SCP(C-Store SCU舷礼,10.3.2.209) C-Store 的狀態(tài)。
在 C-Store 響應之后郊闯,C-Move SCP(10.3.2.209) 會向 C-Move SCU(10.3.13.202)發(fā)送一個 C-Move 響應且轨,內容包括 C-Move 的狀態(tài)浮声、剩余多少個 C-Store 子操作、完成了多少個 C-Store 子操作和失敗了多少個 C-Store 子操作旋奢,詳見上圖紅色框部分泳挥。接下去就又會觸發(fā)另外一個 C-Store 子操作了,數據包和上面的類似至朗,這里不再詳細分析屉符。
上圖是最后一個 C-Store 子操作完成后的 C-Move 響應,這里可以看到狀態(tài)寫的是子操作還在進行中锹引,沒有剩余的子操作了矗钟,完成的子操作是4個。
接著看上圖藍色框的兩行嫌变,當所有的 C-Store 完成后吨艇,為 C-Store 子操作所建立的 Association 連接就會斷開:
- C-Move SCP(C-Store SCU,10.3.2.209)向 C-Move SCU(C-Store SCP腾啥,10.3.13.202) 發(fā)送 A-RELEASE 請求斷開 association东涡;
- C-Move SCU(C-Store SCP,10.3.13.202)響應 C-Move SCP(C-Store SCU倘待,10.3.2.209)的 A-RELEASE 請求疮跑,然后斷開兩個 AE 之間的 association;
斷開這個 association 連接后凸舵, C-Move SCP(C-Store SCU祖娘,10.3.2.209)會向 C-Move SCU(C-Store SCP,10.3.13.202)發(fā)送一個 C-Move 響應啊奄,修改 C-Move 的狀態(tài)為 Success渐苏;
最后紅色框內的兩行是斷開 C-Move 建立的 Association 連接:
- C-Move SCU(10.3.13.202)向 C-Move SCP(10.3.2.209) 發(fā)送 A-RELEASE 請求斷開 association;
- C-Move SCP(10.3.2.209)響應 C-Move SCU(10.3.13.202)的 A-RELEASE 請求菇夸,斷開 C-Move 連接的 association琼富;
以上就是 C-Move 兩方通信詳細交互過程的分析。