基于dcmtk的dicom工具 第八章 echoSCU-dicom测试连接
系列文章目录
文章目录
- 系列文章目录
- 前言
- 一、echoSCU工程流程
- 二、代码
前言
第六章 StoreSCU-图像发送 和 第七章 FindSCU-查询工作列表两篇文章中都有“测试连接”的功能,
其实现方式都是利用dcmtk实现echoSCU功能。
本章单独介绍echoSCU的工作流程。参考dcmtk 源码echoscu.cc,源文件路径dcmtk-3.6.9\dcmnet\apps\echoscu.cc
一、echoSCU工程流程
dcmtk中SCU的流程大同小异。
注意与
第六章 storescu.cc中的主要流程
和
第七章 dcmtk findscu主要流程
对比。
前面1~8步的网络协商流程都一样,只有第8步以后处理不同
- ASC_initializeNetwork初始化网络
- ASC_createAssociationParameters
- ASC_setAPTitles
- ASC_setTransportLayerType
- ASC_setPresentationAddresses
- ASC_addPresentationContext
- ASC_requestAssociation
- ASC_countAcceptedPresentationContexts判断连接是否成功,不成功返回,成功则调用echoSCU测试连接
- echoSCU中调用DIMSE_echoUser真正发送连接测试,检测返回是否连接成功
- 测试连接完成,释放连接,关闭网络
二、代码
BOOL CWlFindSCU::Echo()
{T_ASC_Network *net;T_ASC_Parameters *params;DIC_NODENAME localHost;DIC_NODENAME peerHost;T_ASC_Association *assoc;OFString temp_str;/* initialize network, i.e. create an instance of T_ASC_Network*. */OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Init network failed: \n%s"), temp_str.c_str());return FALSE;}/* initialize asscociation parameters, i.e. create an instance of T_ASC_Parameters*. */cond = ASC_createAssociationParameters(¶ms, ASC_DEFAULTMAXPDU);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Create Association Parameters Failed: %s"), temp_str.c_str());return FALSE;}/* sets this application's title and the called application's title in the params *//* structure. The default values to be set here are "STORESCU" and "ANY-SCP". */ASC_setAPTitles(params, m_param.localAET.c_str(), m_param.remoteAET.c_str(), NULL);/* Set the transport layer type (type of network connection) in the params *//* strucutre. The default is an insecure connection; where OpenSSL is *//* available the user is able to request an encrypted,secure connection. */cond = ASC_setTransportLayerType(params, OFFalse);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Set Transport Layer Type Failed: %s"), temp_str.c_str());return FALSE;}/* Figure out the presentation addresses and copy the *//* corresponding values into the association parameters.*/gethostname(localHost, sizeof(localHost) - 1);sprintf_s(peerHost, "%s:%d", m_param.serverIP.c_str(), m_param.port);ASC_setPresentationAddresses(params, localHost, peerHost);/* Set the presentation contexts which will be negotiated *//* when the network connection will be established */int presentationContextID = 1; /* odd byte value 1, 3, 5, .. 255 */for (unsigned long ii = 0; ii < 1; ii++){cond = ASC_addPresentationContext(params, presentationContextID, UID_VerificationSOPClass,EchotransferSyntaxes, 1);presentationContextID += 2;if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Add Presentation Context Failed: %s"), temp_str.c_str());return FALSE;}}/* dump presentation contexts if required *///OFLOG_DEBUG(echoscuLogger, "Request Parameters:" << OFendl << ASC_dumpParameters(temp_str, params, ASC_ASSOC_RQ));ASC_dumpParameters(temp_str, params, ASC_ASSOC_RQ);Replace(temp_str, _T("\n"), _T("\r\n"));log_debug(_T("Request Parameters:\r\n%s"), temp_str.c_str());/* create association, i.e. try to establish a network connection to another *//* DICOM application. This call creates an instance of T_ASC_Association*. */cond = ASC_requestAssociation(net, params, &assoc);if (cond.bad()){if (cond == DUL_ASSOCIATIONREJECTED){T_ASC_RejectParameters rej;ASC_getRejectParameters(params, &rej);ASC_printRejectParameters(temp_str, &rej);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Association Rejected:\r\n%s"), temp_str.c_str());return FALSE;}else{DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Association Request Failed: %s"), temp_str.c_str());return FALSE;}}/* dump the presentation contexts which have been accepted/refused */ASC_dumpParameters(temp_str, params, ASC_ASSOC_AC);Replace(temp_str, _T("\n"), _T("\r\n"));log_debug(_T("Association Parameters Negotiated:\r\n%s"), temp_str.c_str());/* count the presentation contexts which have been accepted by the SCP *//* If there are none, finish the execution */if (ASC_countAcceptedPresentationContexts(params) == 0){log_error(_T("No Acceptable Presentation Contexts"));return FALSE;}/* dump general information concerning the establishment of the network connection if required */log_debug(_T("Association Accepted (Max Send PDV: %d)"), assoc->sendPDVLength);/* do the real work, i.e. send a number of C-ECHO-RQ messages to the DICOM application *//* this application is connected with and handle corresponding C-ECHO-RSP messages. */cond = echoSCU(assoc);BOOL bEchoOK = FALSE;if (cond == EC_Normal)bEchoOK = TRUE;/* tear down association, i.e. terminate network connection to SCP */if (cond == EC_Normal){/* release association */log_info(_T("Releasing Association"));log_info(_T("连接成功."));cond = ASC_releaseAssociation(assoc);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Association Release Failed: %s"), temp_str.c_str());return bEchoOK;}}else if (cond == DUL_PEERREQUESTEDRELEASE){log_error(_T("Protocol Error: Peer requested release (Aborting)"));log_info(_T("连接失败."));cond = ASC_abortAssociation(assoc);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Association Abort Failed: %s"), temp_str.c_str());return bEchoOK;}}else if (cond == DUL_PEERABORTEDASSOCIATION){log_info(_T("Peer Aborted Association"));log_info(_T("连接失败."));}else{DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Find SCU Failed: %s"), temp_str.c_str());log_info(_T("连接失败."));cond = ASC_abortAssociation(assoc);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Association Abort Failed: %s"), temp_str.c_str());return bEchoOK;}}/* destroy the association, i.e. free memory of T_ASC_Association* structure. This *//* call is the counterpart of ASC_requestAssociation(...) which was called above. */cond = ASC_destroyAssociation(&assoc);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("destroy association failed: %s"), temp_str.c_str());return bEchoOK;}/* drop the network, i.e. free memory of T_ASC_Network* structure. This call *//* is the counterpart of ASC_initializeNetwork(...) which was called above. */cond = ASC_dropNetwork(&net);if (cond.bad()){DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Drop Network Failed: %s"), temp_str.c_str());return bEchoOK;}return bEchoOK;
}OFCondition CWlFindSCU::echoSCU(T_ASC_Association * assoc)
{DIC_US msgId = assoc->nextMsgID++;DIC_US status;DcmDataset *statusDetail = NULL;/* dump information if required */log_info(_T("Sending Echo Request (MsgID %d)"), msgId);/* send C-ECHO-RQ and handle response */OFCondition cond = DIMSE_echoUser(assoc, msgId, DIMSE_BLOCKING, 0, &status, &statusDetail);/* depending on if a response was received, dump some information */if (cond.good()){log_info(_T("Received Echo Response (%s)"), DU_cechoStatusString(status));}else{OFString temp_str;DimseCondition::dump(temp_str, cond);Replace(temp_str, _T("\n"), _T("\r\n"));log_error(_T("Echo Failed: "), temp_str.c_str());}/* check for status detail information, there should never be any */if (statusDetail != NULL){std::ostringstream ostr;ostr << DcmObject::PrintHelper(*statusDetail);log_debug(_T("Status Detail (should never be any):\r\n"), ostr.str().c_str());delete statusDetail;}/* return result value */return cond;
}