DICOM:DICOM3.0网络通信协议之“开源库实现剖析”
背景:
日前,通过对比fo-dicom与dcm4che两种开源库(也是C#与Java两大语言体系)的不同实现来实战学习了DICOM的网络传输,博文中列举了两大开源库各自的实现特点,以及使用的语言特性。本篇继续对比两大开源库,从宏观整体来分析各自DICOM Protocol的实现,聚焦各自使用的线程池,以及管理方式。
ACSE vs DIMSE
DICOM协议是建立在TCP全双工稳定连接之上的,依托于DICOM Upper Layer服务。之前博文DICOM医学图像处理:全面分析DICOM3.0标准中的通讯服务模块中介绍过DICOM协议的整体通信框架,DICOM Upper Layer服务包括A-ASSOCIATE、A-RELEASE、A-ABORT、A-P-ABORT、P-DATA(如下图所示)。
从上图中可以看出除了DICOM Upper Layer的几种服务之外,还有专栏中经常提到的DIMSE-C和DIMSE-N服务,包括C-CTORE、C-GET、C-MOVE、C-FIND、C-ECHO、N-EVENT-REPORT、N-GET、N-SET、N-ACTON、N-CREATE、N-DELETE等11种。那么DIMSE服务与DICOM Upper Layer服务之间有何区别?两者的关系如何呢?——这是初学者最容易混淆的,也最难懂的地方。
为了后面行文方便,直接给出两者关系的整体示意图,详情如下:
该图以fo-dicom为背景,对PDU和DIMSE进行了划分。之前在博文DICOM医学图像处理:DICOM网络传输中介绍过PDU(Protocol Data Unit)和DIMSE(DICOM Message Exchange)的概念,以及简单的对比。从上图可以看出,PDU是Upper Layer 服务层的信息单位,直接建立在TCP连接之上(此处就是.NET中的NetworkStream),其中A-ASSOCIATE、A-RELEASE、A-ABORT等服务直接与TCP连接建立相关。除此以外,有一个特殊的Upper Layer服务,即P-DATA,该服务提供的(或者说该服务具体传输)的就是DIMSE,即DIMSE-C和DIMSE-N。
博文DICOM医学图像处理:DICOM网络传输曾介绍过,DIMSE消息分为Command(必须)和Dataset(可选)两部分, Command用于指出具体服务种类,诸如C-FIND查询、C-STORE存储、C-MOVE提取等等;Dataset给出具体服务的操作数据。言外之意,上图右侧(浅绿色背景)的DIMSE消息是通过P-DATA服务中的PDU传输的,与此同时PDU在具体传输过程中会分成多个PDV(Presentation Data Value)单元。
至此,我们搞清楚了DICOM Upper Layer服务(ACSE)与DIMSE(Command and DataSet)的区别了。
【注】:
在DIMSE(Dicom Message)中有一个字段表示服务状态,即Status,取值为Pending、Success、Failure等(详情见PS3.7附录C),用于两个AE实体间进行状态交互,从而给出相关的处理操作,指的是整个实体交互操作。而PDV中Command和Dataset的MessageControlHeader的isLastFragment与isCommand是用在具体的数据包重组时刻,是在单次DicomMessage中进行的,用于拼接Command+Dataset,或者拼接多个Dataset片段。
两者所用的范围不同,切记。
线程池:fo-dicom vs dcm4che
了解了DICOM通信协议的整体框架,以及消息结构,我们可以分析一下fo-dicom与dcm4che开源库的具体实现方式,如题所言此次从宏观入手,介绍整体的处理流程,尤其是线程池的管理。
1)fo-dicom使用的线程池
在上一篇博文DICOM:DICOM3.0网络通信协议(三)中提到过fo-dicom在实现时并非完全采用.NET的ThreadPool自有线程池,而是在此基础上又添加了一层自己的任务管理,即封装了ThreadPoolQueue< T >任务管理类。这里给出其用意,如下图所示:
DicomService服务使用ThreadPool.QueueUserWorkItem来实现多线程并发。由于DICOM是基于全双工的TCP协议,因此分为客户端和服务端两部分。分为两种情况:
1. 对于客户端发送来的请求:DicomRequest,直接响应并添加到ThreadPool系统线程池中,并不控制执行顺序(这是由于我们无法控制ThreadPool系统线程池的具体执行顺序);
2. 对于发送响应到客户端:DicomResponse,使用ThreadPoolQueue< int >来控制多个响应的顺序执行,具体原理是使用Queue缓存响应消息直至上一个消息处理完成后,具体代码在ThreadPoolQueue类的Execute方法中。
fo-dicom开源库的整个响应流程时序图如下,
由上图可以看出,之所以需要实现自己的任务管理来限定响应的执行顺序,其原因在于fo-dicom开源库使用TCPListener接收到客户端请求后,借用了.NET平台的异步I/O来读取TCP的数据流,.NET平台对于BeginXXX/EndXXX开始的函数也是采用ThreadPool系统线程池来实现的,因此如果后续对于发送到客户端的响应不做约束直接添加到ThreadPool系统线程池中,无法控制各个消息返回客户端的先后顺序(尤其在C-MOVE、C-GET等请求附带C-STORE子操作时)。
【注】:在上一篇博文介绍fo-dicom和dcm4che各自使用的语言特性时提到过MemoryStream。如上图所示,fo-dicom中正是巧妙利用了.NET平台下Stream的seek方法(可自由控制数据流的读取位置)完成PDV的拼接工作。然而Java语言的I/OStream中除了RandomAccessFile以外,无法使用类似seek的指令自由控制流数据读取位置。因此dcm4che开源库中并未出现PDV拼接工作,而是使用的顺序读取解析的方式。——后续有机会会对该部分进行详细介绍。
2)dcm4che使用的线程池
直接给出dcm4che开源库的具体实现时序图,如下所示:
由上图可以看出,dcm4che开源库直接使用的是java语言提供的Executor线程池(具体的是newCachedThreadPool或其他),并且整个方案结构简单。首先与fo-dicom开源库相同,第一层都是依托于TCPListener来响应客户端的请求,不同于fo-dicom采用异步I/O读取NetworkStream的是,dcm4che在接收到客户端的请求后,直接将socket流封装到Association中,随后添加到Executor线程池中,使用DICOM有限状态机(FSM,Finite State Machine)来处理整个DICOM数据流,由于将操作以TCP连接请求为单位进行封装放到Executor线程池的单个线程中执行,外加内部实现的DICOM协议状态机可确保单个连接之上的执行逻辑,因此不需要像fo-dicom中自定义任务管理来控制执行流程。
【注】:dcm4che巧妙的利用的Java语言的enum特性,实现了DICOM协议有限状态机(详情参考博文DICOM:DICOM3.0网络通信协议(续)),以此来管理整个DICOM请求和响应的执行流程——后续有机会同样会对该部分进行详细介绍。
作者:zssure@163.com
时间:2015-11-26
DICOM:DICOM3.0网络通信协议之“开源库实现剖析”相关推荐
- DICOM:DICOM3.0网络通信协议(三)
背景: 专栏对于DICOM网络传输介绍过多次,例如DICOM:DICOM3.0网络通信协议(续).DICOM医学图像处理:DICOM网络传输.DICOM医学图像处理:全面分析DICOM3.0标准中的通 ...
- 几个可以画网络拓扑图的开源库
之前做个监控系统,需要在GUI客户端有个网络拓扑结构图,实时显示被监控节点的连接情况, 支持动态增减监控节点,能够在拓扑图上自动布局.找到了三个比较合适的库: SWT的ZEST : 基于draw2D库 ...
- DICOM:DICOM开源库多线程分析之“ThreadPoolQueue in fo-dicom”
背景: 上篇博文介绍了dcm4chee中使用的Leader/Follower线程池模型,主要目的是节省上下文切换,提高运行效率.本博文同属[DICOM开源库多线程分析]系列,着重介绍fo-dicom中 ...
- 常用C/C++开源库
1. 框架 Apache C++ Standard Library : 是一系列算法,容器,迭代器和其他基本组件的集合 ASL : Adobe源代码库提供了同行的评审和可移植的C++源代码库. Boo ...
- C++开源库大全(转)
http://blog.csdn.net/chen19870707/article/details/40427645 程序员要站在巨人的肩膀上,C++拥有丰富的开源库,这里包括:标准库.Web应用框架 ...
- C++跨平台开源库 之二
值得学习的C/C++语言开源项目 (1)ACE 庞大.复杂,适合大型项目.开源.免费,不依赖第三方库,支持跨平台. http://www.cs.wustl.edu/~schmidt/ACE.html ...
- C 和 C++ 开源库的清单
关于 C++ 框架.库和资源的一些汇总列表,由 fffaraz(GitHub - fffaraz/awesome-cpp: A curated list of awesome C++ (or C) f ...
- 【Android 安全】DEX 加密 ( 代理 Application 开发 | 项目中配置 OpenSSL 开源库 | 使用 OpenSSL 开源库解密 dex 文件 )
文章目录 一.项目中配置 OpenSSL 开源库 二.OpenSSL 开源库解密参考代码 三.解密 dex 文件的 Java 代码 四.解密 dex 文件的 Jni 代码 参考博客 : [Androi ...
- 【转】DCMTK开源库类继承结构与DICOM3.0标准元素定义的对应关系图
转自:https://blog.csdn.net/zssureqh/article/details/9275271 最近由于课题需要,拿出来一些时间阅读了下DICOM3.0标准.在处理相关的DCM医学 ...
最新文章
- 算法(第4版)Algorithms, Fourth Edition
- 高并发核心Selector详解
- Python 过滤字母和数字
- 汇编语言 + Visual Studio 2019——Visual Studio 2019 中汇编语言环境解决方案
- $arr[]=$v 把 $v 这个东西 放到 $arr[] 这个数组中
- ExtJs 备忘录(1)—— Form表单(一) [ 控件使用 ]
- 赣南师范学院数学竞赛培训第10套模拟试卷参考解答
- 明锐旅行车又大又便宜,值得买吗?
- Web项目--------原Oracle数据库的项目同时兼容MySql
- 4.软件架构设计:大型网站技术架构与业务架构融合之道 --- 操作系统
- 面试题-mysql优化
- wordpress登录美化css,wordpress后台login界面美化
- SIPp 安装及使用
- RealMedia Analyzer(mp4修复软件)v0.30绿色版
- 普华永道:AI到2030年将带动全球GDP增长14%,中国成最大受益国
- 清华大学计算机与科学系张荷花简历,清华大学软件学院
- 【M365运维】匹配用户UPN和Email地址
- Linux计划任务介绍
- 拼多多的店铺怎样引流和出价-纽黑文教学
- 不一般的Cover Letter