本文主要描述,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;
来源:https://www.cnblogs.com/wang_xy/p/12015328.html