Отправка файла dicom в удаленную AE с помощью C# в Visual Studio 2010
Моя цель - отправить файл dicom в удаленную AE с помощью C# в Visual Studio 2010, я планирую реализовать библиотеку clearcanvas, я разделил задачу на 5 частей:
// //1 initiate tcp\ip connection
// //2 negotiate the association parameters to agree what can be done
// //3 send the dicom object
// //4 close the association
// //5 close the TCP/IP connection
Я знаю, что Storagescu будет участвовать в отправке part3), я пытался найти что-то на форуме clearcanvas, коды пока не имеют особого смысла, поэтому я не знаю, с чего начать, может кто-нибудь, кто имел опыт отправки файла dicom отдалённому человеку, дайте некоторую подсказку о том, как я должен даже сделать свое исследование? я на правильном пути?
Ваша помощь будет принята с благодарностью!
1 ответ
Я построил это на Clear Canvas специально для возможности отправки очень больших файлов. Другие программы, которые я написал, не работали с изображениями большого размера, поэтому я сделал урезанную версию для отправки файлов DICOM размером несколько ГБ, и это сработало. Только командная строка и program.cs в этой программе. Это самый простой ответ на вопрос о том, как отправить файл DICOM с помощью Clear Canvas.
Есть одна вещь, которую стоит отметить. Вам нужен способ связи между потоком, запускающим запрос, и Clear Canvas, в этом случае запрос C-Store из program.cs и класс AssociationHandler: IDicomClientHandler.
Здесь я просто использую Boolean и цикл while, прежде чем позволить потоку, создающему запрос, продолжить работу. В других программах я использовал многомерный массив строк для хранения значений для каждой ассоциации, и я могу выполнить любую операцию DICOM, C-Store, C-Move, C-Find, N-Action, ect, в многопоточном мода с прозрачным холстом Просто нет лучшего инструментария DICOM с открытым исходным кодом.
Все, что вам нужно сделать, чтобы запустить этот код, это создать консольное приложение и обработать ссылки на библиотеки Clear Canvas. Пожалуйста, задавайте любые вопросы.
Аргументы командной строки перечислены в коде для вывода справки.
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Data;
using ClearCanvas.Dicom;
using System.IO;
using System.Diagnostics;
using ClearCanvas.Dicom.Network;
using ClearCanvas.Common;
using System.Net;
using System.Threading;
namespace CC_SendFile
{
class Program
{
public static Boolean C_Store_Response = false;
public static Boolean Assoc_Accept_Reject = false;
public static Boolean NetworkError = false;
public static String FilePath = null;
public static String LocalAE = null;
public static String RemoteAE = null;
public static String RemoteIP = null;
public static String RemotePort = null;
public static uint MaxPDUSize = 0;
public static int MaxPDUTimeoutMilliSeconds = 30000;
static void Main(string[] args)
{
if (args.Length != 0)
{
String ProcessID = null;
System.Diagnostics.Process myProcess = System.Diagnostics.Process.GetCurrentProcess();
ProcessID = "[" + myProcess.Id.ToString() + "] ";
myProcess.Close();
myProcess.Dispose();
Platform.Log(LogLevel.Debug, "Process ID obtained for title bar and logging is: " + ProcessID);
log4net.GlobalContext.Properties["procid"] = ProcessID;
for (int i = 0; i < args.Length - 1; i++)
{
String ArgTemp = null;
ArgTemp = args[i];
if (ArgTemp == "-l")
{
LocalAE = args[i + 1];
i++;
}
if (ArgTemp == "-r")
{
RemoteAE = args[i + 1];
i++;
}
if (ArgTemp == "-h")
{
RemoteIP = args[i + 1];
i++;
}
if (ArgTemp == "-p")
{
RemotePort = args[i + 1];
i++;
}
if (ArgTemp == "-f")
{
FilePath = args[i + 1];
i++;
}
if (ArgTemp == "-u")
{
MaxPDUSize = uint.Parse(args[i + 1]);
i++;
}
if (ArgTemp == "-n")
{
MaxPDUTimeoutMilliSeconds = int.Parse(args[i + 1]);
}
}//for (int i = 1; i < args.Length - 1; i++)
ClientAssociationParameters g_assocParams = null;
DicomClient g_dicomClient = null;
IPAddress addr = null;
foreach (IPAddress dnsAddr in Dns.GetHostAddresses(RemoteIP))
if (dnsAddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
addr = dnsAddr;
Platform.Log(LogLevel.Info , "IP address found to use is: " + addr.ToString());
break;
}
if (addr == null)
{
Platform.Log(LogLevel.Error, "No Valid IP addresses for host {0}", RemoteIP);
return;
}
g_assocParams = new ClientAssociationParameters(LocalAE, RemoteAE, new IPEndPoint(addr, int.Parse(RemotePort)));
if (MaxPDUSize != 0)
{
g_assocParams.LocalMaximumPduLength = MaxPDUSize;
Console.WriteLine("LocalMaximumPduLength has been set to: " + g_assocParams.LocalMaximumPduLength.ToString());
Platform.Log(LogLevel.Info, "LocalMaximumPduLength has been set to: " + g_assocParams.LocalMaximumPduLength.ToString());
}
else
{
Console.WriteLine("LocalMaximumPduLength is by default: " + g_assocParams.LocalMaximumPduLength.ToString());
Platform.Log(LogLevel.Info, "LocalMaximumPduLength is by default: " + g_assocParams.LocalMaximumPduLength.ToString());
}
try
{
Console.WriteLine("");
Console.WriteLine("Loading File: " + FilePath + ", please wait...");
Console.WriteLine("");
Platform.Log(LogLevel.Info, "Loading File: " + FilePath + ", please wait...");
DicomFile DF = new DicomFile(FilePath);
GC.AddMemoryPressure(1047881834);
try
{
//DF.Load(DicomReadOptions.KeepGroupLengths);
DF.Load(DicomReadOptions.Default);
}
catch (Exception eL)
{
}
Console.WriteLine("SOP Class: " + DF.SopClass.ToString());
Console.WriteLine("Transfer Syntax: " + DF.TransferSyntax.ToString ());
Platform.Log(LogLevel.Info, "SOP Class: " + DF.SopClass.ToString());
Platform.Log(LogLevel.Info, "Transfer Syntax: " + DF.TransferSyntax.ToString());
byte pcid = g_assocParams.AddPresentationContext(DF.SopClass);
g_assocParams.AddTransferSyntax(pcid, DF.TransferSyntax);
DicomMessage msg = new DicomMessage(DF);
DF = null;
GC.Collect();
GC.WaitForPendingFinalizers();
AssociationHandler handler = new AssociationHandler();
Console.WriteLine("Attempting to connect to remote AE.");
Platform.Log(LogLevel.Info, "Attempting to connect to remote AE.");
g_dicomClient = DicomClient.Connect(g_assocParams, (IDicomClientHandler)handler);
while (Assoc_Accept_Reject == false)
{
Console.WriteLine("Waiting for Association to be accepted or rejected.");
Platform.Log(LogLevel.Info, "Waiting for Association to be accepted or rejected.");
Thread.Sleep(1000);
}
try
{
if (MaxPDUTimeoutMilliSeconds != 0)
{
g_dicomClient.InternalSocket.SendTimeout = MaxPDUTimeoutMilliSeconds;
g_dicomClient.InternalSocket.ReceiveTimeout = MaxPDUTimeoutMilliSeconds;
Console.WriteLine("Internal Socket Send/Receive Timeout has been set to: " + g_dicomClient.InternalSocket.SendTimeout.ToString() + " ms.");
Platform.Log(LogLevel.Info, "Internal Socket Send/Receive Timeout has been set to: " + g_dicomClient.InternalSocket.SendTimeout.ToString() + " ms.");
g_dicomClient.InternalSocket.SendTimeout = MaxPDUTimeoutMilliSeconds;
}
Console.WriteLine("Sending C-Store Request.");
Platform.Log(LogLevel.Info, "Sending C-Store Request.");
g_dicomClient.SendCStoreRequest(pcid, g_dicomClient.NextMessageID(), DicomPriority.Medium, msg);
}
catch (Exception eS)
{
Console.WriteLine("Error sending C-Store Request.");
Console.WriteLine(eS.ToString());
Platform.Log(LogLevel.Error, "Error sending C-Store Request. The error is: " + eS.ToString ());
}
while (C_Store_Response == false)
{
Console.WriteLine("Waiting for C-Store response.");
Platform.Log(LogLevel.Info, "Waiting for C-Store response.");
Thread.Sleep(1000);
}
if (NetworkError == false)
{
Console.WriteLine("Sending release request.");
Platform.Log(LogLevel.Info, "Sending release request.");
g_dicomClient.SendReleaseRequest();
}
Thread.Sleep(1000);
Console.WriteLine("Operations have completed.");
Console.WriteLine("Press ENTER to exit!");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error reading file. The error is:");
Console.WriteLine("");
Console.WriteLine(e.Message);
Console.WriteLine("");
Console.WriteLine("Stack Trace:");
Console.WriteLine(e.ToString());
Console.WriteLine("Press ENTER to exit!");
Console.ReadLine();
Platform.Log(LogLevel.Error, "Error reading file. The error is:");
Platform.Log(LogLevel.Error, e.ToString());
}
}//if (args .Length != 0 )
else
{
Console.WriteLine ("You must provide the proper command line arguments.");
Console.WriteLine ("Required arguments are:");
Console.WriteLine ("");
Console.WriteLine ("-f [full file path to DCM file] (No whitespaces please!)");
Console.WriteLine ("-l [Local AE Title]");
Console.WriteLine ("-r [Remote AE Title]");
Console.WriteLine ("-h [Remote HostName or IP address]");
Console.WriteLine ("-p [Remote Port]");
Console.WriteLine ("");
Console.WriteLine("Press ENTER to exit!");
Console.ReadLine();
Platform.Log(LogLevel.Error, "You must provide the proper command line arguments.");
Platform.Log(LogLevel.Error, "Required arguments are:");
Platform.Log(LogLevel.Error, "");
Platform.Log(LogLevel.Error, " -f [full file path to DCM file] (No whitespaces please!)");
Platform.Log(LogLevel.Error, " -l [Local AE Title]");
Platform.Log(LogLevel.Error, " -r [Remote AE Title]");
Platform.Log(LogLevel.Error, " -h [Remote HostName or IP address]");
Platform.Log(LogLevel.Error, " -p [Remote Port]");
Platform.Log(LogLevel.Error, "");
}
}//static void Main(string[] args)
class AssociationHandler : IDicomClientHandler
{
#region IDicomClientHandler Members
public void OnReceiveAssociateAccept(DicomClient client, ClientAssociationParameters association)
{
Console.WriteLine("Association was accepted!");
Platform.Log(LogLevel.Info, "Association was accepted!");
Assoc_Accept_Reject = true;
}
public void OnReceiveAssociateReject(DicomClient client, ClientAssociationParameters association, DicomRejectResult result, DicomRejectSource source, DicomRejectReason reason)
{
Console.WriteLine("Association was rejected!");
Platform.Log(LogLevel.Info, "Association was rejected!");
Assoc_Accept_Reject = true;
}
public void OnReceiveRequestMessage(DicomClient client, ClientAssociationParameters association, byte presentationID, DicomMessage message)
{
}
public void OnReceiveResponseMessage(DicomClient client, ClientAssociationParameters association, byte presentationID, DicomMessage message)
{
if (message.Status.Status == DicomState.Success)
{
Console.WriteLine("DICOM success message received!");
Platform.Log(LogLevel.Info, "DICOM success message received!");
C_Store_Response = true;
}
if (message.Status.Status != DicomState.Failure)
{
Console.WriteLine("DICOM faliure message received!");
Platform.Log(LogLevel.Info, "DICOM faliure message received!");
C_Store_Response = true;
}
}
public void OnReceiveReleaseResponse(DicomClient client, ClientAssociationParameters association)
{
Console.WriteLine("Received Release Response.");
Platform.Log(LogLevel.Info, "Received Release Response.");
}
public void OnReceiveAbort(DicomClient client, ClientAssociationParameters association, DicomAbortSource source, DicomAbortReason reason)
{
}
public void OnNetworkError(DicomClient client, ClientAssociationParameters association, Exception e)
{
Console.WriteLine("Network Error occured.");
Platform.Log(LogLevel.Info, "Network Error occured.");
try
{
Platform.Log(LogLevel.Info, "Attempting to get error message...");
Platform.Log(LogLevel.Error, e.ToString ());
}
catch (NullReferenceException)
{
Platform.Log(LogLevel.Error, "The error message was null.");
}
C_Store_Response = true;
NetworkError = true;
}
public void OnDimseTimeout(DicomClient client, ClientAssociationParameters association)
{
Platform.Log(LogLevel.Error, "DimseTimeout occured on client. Continuing...");
}
#endregion
}
}//class Program
}//namespace CC_SendFile