本文主要描述,dicom通信的scu,scp的c-echo、c-store、c-find、c-move的使用。

DicomService
IDicomServiceProvider
IDicomCStoreProvider
IDicomCEchoProvider
IDicomCFindProvider
IDicomCMoveProvider
IDicomTransformRule

(1)c-echo

 客户端代码:

 1  DicomClient client = new DicomClient();
 2                 client.AssociationAccepted += Client_AssociationAccepted;
 3                 client.AssociationRejected += Client_AssociationRejected;
 4                 client.AssociationReleased += Client_AssociationReleased;
 5                 client.NegotiateAsyncOps();
 6                 client.AddRequest(new DicomCEchoRequest());
 7
 8
 9                 //client.Send
10                 client.SendAsync(ae_dest.ip,
11                     ae_dest.port,
12                     false,
13                     ae_src.name,//SCU
14                     ae_dest.name//ANY-SCP
15                     );
 1 private void Client_AssociationReleased(object sender, EventArgs e)
 2 {
 3     //string log = $"Client_AssociationReleased --> {e}";
 4     //AppendLog(log);
 5 }
 6
 7 private void Client_AssociationRejected(object sender, AssociationRejectedEventArgs e)
 8 {
 9     string log = $"Client_AssociationRejected --> {e}";
10     AppendLog("echo ng");
11 }
12
13 private void Client_AssociationAccepted(object sender, AssociationAcceptedEventArgs e)
14 {
15     string log = $"Client_AssociationAccepted  --> {e}";
16     AppendLog("echo ok");
17 }

(2)c-store

客户端代码:

 1 private void SendOne(Switch_Dicom_Image entity)
 2         {
 3             string fileReal = Path.Combine(AppSettings.dicom_path_root, entity.FilePath);
 4
 5             var destServer = dao.GetOneDestSwitchAETitle(entity.SrcAETitle);
 6
 7             string aet_current = AppSettings.scp_aet;
 8
 9             string[] files = new string[] { fileReal };
10
11             int expected = files.Length;
12             var actual = 0;
13
14             var client = new DicomClient();
15             client.NegotiateAsyncOps(expected, 1);
16
17             foreach (string file in files)
18             {
19                 try
20                 {
21                     Log($"正在发送文件“{file}”");
22
23                     DicomCStoreRequest req = new DicomCStoreRequest(file);
24                     req.OnResponseReceived = (req2, res) =>
25                     {
26                         try
27                         {
28                             Interlocked.Increment(ref actual);
29
30                             string log = $"OnResponseReceived --> 【{actual}】 {res.Status} {req2.SOPInstanceUID.UID}";
31                             Log(log);
32
33                             if (res.Status == DicomStatus.Success)
34                             {
35                                 using (var dbContext = new StudyProEntities())
36                                 {
37                                     var record = dbContext.Switch_Dicom_Image.Where(one => one.ImageGUID == entity.ImageGUID).FirstOrDefault();
38                                     record.SendStatus = 1;
39                                     record.SendCount = record.SendCount + 1;
40                                     record.SendTime = DateTime.Now;
41                                     int n = dbContext.SaveChanges();
42                                     if (n > 0)
43                                     {
44                                         //将接受目录下的文件给删除
45                                         File.Delete(file);
46                                     }
47
48                                 }//end using
49
50                             }
51                             else
52                             {
53                                 using (var dbContext = new StudyProEntities())
54                                 {
55                                     var record = dbContext.Switch_Dicom_Image.Where(one => one.ImageGUID == entity.ImageGUID).FirstOrDefault();
56                                     record.SendStatus = 2;
57                                     record.SendCount = record.SendCount + 1;
58                                     record.SendError = $"{res.Status}";
59                                     int n = dbContext.SaveChanges();
60                                     if (n > 0)
61                                     {
62                                         //失败不能删除文件
63                                     }
64
65                                 }//end using
66                             }
67                         }
68                         catch (Exception ex)
69                         {
70                             LogHelper.Instance.Fatal(ex.ToString());
71                         }
72
73                     };
74
75                     client.AddRequest(req);
76
77                     //client.SendAsync(
78                     client.Send(
79                     destServer.IPAddress,
80                     destServer.Port,
81                     false,
82                     aet_current,//SCU
83                     destServer.AETitle,//ANY-SCP
84                     timeout
85                     );
86                 }
87                 catch (Exception ex)
88                 {
89                     LogHelper.Instance.Fatal(ex.ToString());
90                 }
91
92             }//end foreach
93         }

服务端代码:

 1  mActionLog?.Invoke("接收到待处理的 DicomCStoreRequest...");
 2
 3             bool b = false;
 4
 5             string pPatientID = "";
 6             b = request.Dataset.TryGetValue<string>(DicomTag.PatientID, 0, out pPatientID);
 7             if (!b)
 8             {
 9                 throw new Exception("未能识别 PatientID");
10             }
11             mActionLog?.Invoke($"pPatientID={pPatientID}");
12
13             string pStudyInstanceUID = "";
14             b = request.Dataset.TryGetValue<string>(DicomTag.StudyInstanceUID, 0, out pStudyInstanceUID);
15             if (!b)
16             {
17                 throw new Exception("未能识别 StudyInstanceUID");
18             }
19             mActionLog?.Invoke($"pStudyInstanceUID={pStudyInstanceUID}");
20
21             string pSeriesInstanceUID = "";
22             b = request.Dataset.TryGetValue<string>(DicomTag.SeriesInstanceUID, 0, out pSeriesInstanceUID);
23             if (!b)
24             {
25                 throw new Exception("未能识别 SeriesInstanceUID");
26             }
27             mActionLog?.Invoke($"pSeriesInstanceUID={pSeriesInstanceUID}");
28
29             string pSOPInstanceUID = "";
30             b = request.Dataset.TryGetValue<string>(DicomTag.SOPInstanceUID, 0, out pSOPInstanceUID);
31             if (!b)
32             {
33                 throw new Exception("未能识别 pSOPInstanceUID");
34             }
35
36             mActionLog?.Invoke($"pSOPInstanceUID={pSOPInstanceUID}");
37
38
39             string file = "";
40
41             string pathLocalCache = App.gPathLocalCache;//Path.Combine(Application.StartupPath, "Cache");
42
43             string pathRelative = "";
44             //pathRelative = $"{pStudyInstanceUID}/{pSeriesInstanceUID}/{pSOPInstanceUID}.dcm";
45             pathRelative = $"{pStudyInstanceUID}/{pSOPInstanceUID}.dcm";
46
47             file = Path.Combine(pathLocalCache, pathRelative);
48
49             var dir = Path.GetDirectoryName(file);
50             if (!Directory.Exists(dir))
51             {
52                 Directory.CreateDirectory(dir);
53             }
54
55             if (File.Exists(file))
56             {
57                 File.Delete(file);
58             }
59
60             request.File.Save(file);

(3)c-find

客户端代码:

 1         public List<DicomDataset> GetData(AEInfo ae, DicomCFindRequest dicomCFindRequest)
 2         {
 3             ManualResetEvent mre = new ManualResetEvent(false);
 4             List<DicomDataset> list = new List<DicomDataset>();
 5
 6             dicomCFindRequest.OnResponseReceived =
 7                 (DicomCFindRequest request, DicomCFindResponse response) =>
 8                 {
 9                     Debug.WriteLine($"Status={response.Status}");
10
11                     if (response.Status == DicomStatus.Success
12                         || response.Status == DicomStatus.ProcessingFailure)
13                     {
14                         mre.Set();
15                         return;
16                     }
17
18                     //输出值信息
19                     response.ToString(true);
20
21                     if (response.HasDataset)
22                     {
23
24                         list.Add(response.Dataset);
25                     }
26                 };
27
28             //发起C-FIND-RQ,用A-ASSOCIATE服务建立DICOM实体双方之间的连接
29             var client = new DicomClient();
30             //client.NegotiateAsyncOps();
31
32             client.AddRequest(dicomCFindRequest);
33
34             client.Send(host: ae.ip,//127.0.0.1
35                 port: ae.port,
36                 useTls: false,
37                 callingAe: local_aet,//SCU-AE
38                 calledAe: ae.name//SCP-AE
39                 );
40
41             bool b = mre.WaitOne(1000 * 10);
42             if (!b)
43             {
44                 MessageBox.Show("查询超时,请重试!");
45                 return null;
46             }
47
48             return list;

服务端代码: 

 1 DicomStatus status = DicomStatus.Success;
 2
 3             List<DicomCFindResponse> list = new List<DicomCFindResponse>();
 4
 5             try
 6             {
 7                 if (UserCustomCFindRequestHandle != null)
 8                 {
 9                     IList<DicomDataset> data = UserCustomCFindRequestHandle(request);
10                     if (data != null)
11                     {
12                         LogHelper.Instance.Debug($"OnCFindRequest 结果的记录数为 {data.Count}");
13
14                         foreach (var one in data)
15                         {
16                             DicomCFindResponse rsp = new DicomCFindResponse(request, DicomStatus.Pending);
17                             rsp.Dataset = one;
18                             list.Add(rsp);
19                         }
20                     }
21                     else
22                     {
23                         status = DicomStatus.QueryRetrieveOutOfResources;
24                     }
25                 }
26             }
27             catch (Exception ex)
28             {
29                 LogHelper.Instance.Error(ex.ToString());
30                 list.Clear();
31                 status = DicomStatus.ProcessingFailure;
32             }
33
34             //DicomStatus.QueryRetrieveOutOfResources
35
36             list.Add(new DicomCFindResponse(request, status));

(4)c-move

客户端代码:

 1  var requestCMove = new DicomCMoveRequest(ae_dest.name, studyInstanceUid, seriesInstanceUid, sopInstanceUid);
 2
 3                 var id = requestCMove.MessageID;
 4
 5                 requestCMove.OnResponseReceived = (DicomCMoveRequest request, DicomCMoveResponse response) =>
 6                 {
 7                     string log = $"OnResponseReceived --> {response.Status} | Completed={ response.Completed }, Remaining={ response.Remaining }, Failures={ response.Failures }, Warnings={ response.Warnings }";
 8                     this.AppendLog(log);
 9
10                     //sopInstanceUID
11                     if (response.Status == DicomStatus.Pending)
12                     {
13                         if(response.Dataset!=null)
14                         {
15                             string key = response.Dataset.GetString(DicomTag.SOPInstanceUID);
16                             if (!string.IsNullOrEmpty(key))
17                             {
18                                 mActionRun?.Invoke(key);
19                             }
20                         }
21                     }
22
23                 };
24
25                 var client = new DicomClient();
26                 client.AddRequest(requestCMove);
27
28                 //client.Send
29                 client.SendAsync(ae_dest.ip,
30                     ae_dest.port,
31                     false,
32                     ae_src.name,//SCU-AE
33                     ae_dest.name//SCP-AE
34                     );

服务端代码:

  1  string aet_current = this.Association.CalledAE;
  2             string aet_remote = this.Association.CallingAE;
  3
  4             Sys_AETitle ae = UserCustomApplicationEntityTitleHandle(aet_remote);
  5
  6
  7             //AE Title 长度不能太长,这个是最长的长度,比如:“xxx_client_tool_”,最长16个字符。
  8
  9             LogHelper.Instance.Debug($"根据{aet_remote}查找到的ae --> {JsonConvert.SerializeObject(ae)}");
 10
 11
 12             DicomStatus status = DicomStatus.Success;
 13             IList<DicomCMoveResponse> listResponse = new List<DicomCMoveResponse>();
 14
 15
 16             IList<CMoveReturnInfo> listFind;
 17
 18             //DicomClient client = new DicomClient();
 19
 20             if (UserCustomCMoveRequestHandle != null)
 21             {
 22                 listFind = UserCustomCMoveRequestHandle(request);
 23
 24                 if (listFind != null
 25                     && listFind.Count > 0)
 26                 {
 27                     int len = listFind.Count;
 28
 29                     LogHelper.Instance.Debug($"cmove-cstore给客户端文件数为 {len}");
 30
 31                     int nRemaining = len;
 32                     int nFailures = 0;
 33                     int nWarnings = 0;
 34                     int nCompleted = 0;
 35
 36                     if (true)
 37                     {
 38                         DicomCMoveResponse responseCMove = new DicomCMoveResponse(request, DicomStatus.Pending);
 39                         responseCMove.Remaining = nRemaining;
 40                         responseCMove.Completed = nCompleted;
 41                         responseCMove.Warnings = nWarnings;
 42                         responseCMove.Failures = nFailures;
 43
 44                         base.SendResponseAsync(responseCMove);
 45                         //SendResponse(responseCMove);
 46                     }//end if
 47
 48
 49                     foreach (var one in listFind)
 50                     {
 51                         try
 52                         {
 53                             string path = AppSettings.dicom_path_root;
 54
 55                             string file = Path.Combine(path, one.DomainID, one.StudyDateTime.Value.ToString("yyyyMMdd"), one.SysStudyGUID, one.SOPInstanceUID + ".dcm");
 56
 57
 58                             if (!File.Exists(file))
 59                             {
 60                                 lock (_objLock)
 61                                 {
 62                                     nFailures++;
 63                                 }
 64
 65                                 throw new Exception($"文件不存在 {file}");
 66                             }
 67
 68                             DicomCStoreRequest dicomCStoreRequest = new DicomCStoreRequest(file);
 69                             //读取了dcm文件后,dicomCStoreRequest.Dataset的值将从file读取填充
 70                             //dicomCStoreRequest.Dataset.Add(DicomTag.XXX, XXX);
 71
 72
 73                             dicomCStoreRequest.OnResponseReceived = (rq, rs) =>
 74                             {
 75                                 LogHelper.Instance.Debug($"dicomCStoreRequest --> {rs.Status}");
 76
 77                                 if (rs.Status == DicomStatus.Success)
 78                                 {
 79                                     lock (_objLock)
 80                                     {
 81                                         nCompleted++;
 82
 83                                         nRemaining = len - nFailures - nWarnings - nCompleted;
 84                                     }
 85
 86                                     //--------------------------------------------------------------------
 87                                     if (true)
 88                                     {
 89                                         DicomCMoveResponse response = new DicomCMoveResponse(request, DicomStatus.Pending);
 90                                         response.Remaining = nRemaining;
 91                                         response.Completed = nCompleted;
 92                                         response.Warnings = nWarnings;
 93                                         response.Failures = nFailures;
 94
 95
 96                                         //将一些信息返回给客户端,作为客户端确认相关操作使用
 97                                         response.Dataset = new DicomDataset();
 98                                         response.Dataset.Add(DicomTag.SOPInstanceUID, one.SOPInstanceUID);
 99                                         response.Dataset.Add(DicomTag.StudyInstanceUID, one.StudyInstanceUID);
100                                         response.Dataset.Add(DicomTag.SeriesInstanceUID, one.SeriesInstanceUID);
101                                         response.Dataset.Add(DicomTagVNA.CMoveServerFilePath, file);
102
103                                         base.SendResponseAsync(response);
104                                         //SendResponse(rsponse);
105                                     }//end if
106                                      //--------------------------------------------------------------------
107                                 }
108                                 else
109                                 {
110                                     LogHelper.Instance.Debug($"cmove-cstore给客户端返回失败({rs.Status})");
111                                 }
112
113
114                             };
115
116
117                             try
118                             {
119                                 LogHelper.Instance.Debug($"发送文件 --> {file}");
120
121                                 DicomClient client = new DicomClient();
122                                 client.AddRequest(dicomCStoreRequest);
123
124                                 client.Send(
125                                     ae.IPAddress,
126                                     ae.Port,
127                                     false,
128                                     aet_current,
129                                     aet_remote
130                                     );
131                             }
132                             catch (Exception ex)
133                             {
134                                 LogHelper.Instance.Debug("cmove发送给客户端失败 --> " + ex.ToString());
135                                 throw ex;
136                             }
137
138                         }
139                         catch (Exception ex)
140                         {
141                             Debug.WriteLine(ex.ToString());
142
143                             DicomCMoveResponse rs = new DicomCMoveResponse(request, DicomStatus.StorageStorageOutOfResources);
144                             listResponse.Add(rs);
145
146                             return listResponse;
147
148                         }
149                         finally
150                         {
151
152                         }
153
154                     }//end foreach
155
156                     listResponse.Add(new DicomCMoveResponse(request, DicomStatus.Success));
157                     return listResponse;
158
159                 }
160             }
161
162             listResponse.Add(new DicomCMoveResponse(request, DicomStatus.NoSuchObjectInstance));
163             return listResponse;
02-09 19:54