背景:

日前,通过对比fo-dicom与dcm4che两种开源库(也是C#与Java两大语言体系)的不同实现来实战学习了DICOM的网络传输,博文中列举了两大开源库各自的实现特点,以及使用的语言特性。本篇继续对比两大开源库,从宏观整体来分析各自DICOM Protocol的实现,聚焦各自使用的线程池,以及管理方式。

ACSE vs DIMSE

DICOM协议是建立在TCP全双工稳定连接之上的,依托于DICOM Upper Layer服务。之前博文DICOM医学图像处理:全面分析DICOM3.0标准中的通讯服务模块中介绍过DICOM协议的整体通信框架,DICOM Upper Layer服务包括A-ASSOCIATEA-RELEASEA-ABORTA-P-ABORTP-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的isLastFragmentisCommand是用在具体的数据包重组时刻,是在单次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网络通信协议之“开源库实现剖析”相关推荐

  1. DICOM:DICOM3.0网络通信协议(三)

    背景: 专栏对于DICOM网络传输介绍过多次,例如DICOM:DICOM3.0网络通信协议(续).DICOM医学图像处理:DICOM网络传输.DICOM医学图像处理:全面分析DICOM3.0标准中的通 ...

  2. 几个可以画网络拓扑图的开源库

    之前做个监控系统,需要在GUI客户端有个网络拓扑结构图,实时显示被监控节点的连接情况, 支持动态增减监控节点,能够在拓扑图上自动布局.找到了三个比较合适的库: SWT的ZEST : 基于draw2D库 ...

  3. DICOM:DICOM开源库多线程分析之“ThreadPoolQueue in fo-dicom”

    背景: 上篇博文介绍了dcm4chee中使用的Leader/Follower线程池模型,主要目的是节省上下文切换,提高运行效率.本博文同属[DICOM开源库多线程分析]系列,着重介绍fo-dicom中 ...

  4. 常用C/C++开源库

    1. 框架 Apache C++ Standard Library : 是一系列算法,容器,迭代器和其他基本组件的集合 ASL : Adobe源代码库提供了同行的评审和可移植的C++源代码库. Boo ...

  5. C++开源库大全(转)

    http://blog.csdn.net/chen19870707/article/details/40427645 程序员要站在巨人的肩膀上,C++拥有丰富的开源库,这里包括:标准库.Web应用框架 ...

  6. C++跨平台开源库 之二

    值得学习的C/C++语言开源项目 (1)ACE 庞大.复杂,适合大型项目.开源.免费,不依赖第三方库,支持跨平台. http://www.cs.wustl.edu/~schmidt/ACE.html ...

  7. C 和 C++ 开源库的清单

    关于 C++ 框架.库和资源的一些汇总列表,由 fffaraz(GitHub - fffaraz/awesome-cpp: A curated list of awesome C++ (or C) f ...

  8. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 项目中配置 OpenSSL 开源库 | 使用 OpenSSL 开源库解密 dex 文件 )

    文章目录 一.项目中配置 OpenSSL 开源库 二.OpenSSL 开源库解密参考代码 三.解密 dex 文件的 Java 代码 四.解密 dex 文件的 Jni 代码 参考博客 : [Androi ...

  9. 【转】DCMTK开源库类继承结构与DICOM3.0标准元素定义的对应关系图

    转自:https://blog.csdn.net/zssureqh/article/details/9275271 最近由于课题需要,拿出来一些时间阅读了下DICOM3.0标准.在处理相关的DCM医学 ...

最新文章

  1. 算法(第4版)Algorithms, Fourth Edition
  2. 高并发核心Selector详解
  3. Python 过滤字母和数字
  4. 汇编语言 + Visual Studio 2019——Visual Studio 2019 中汇编语言环境解决方案
  5. $arr[]=$v 把 $v 这个东西 放到 $arr[] 这个数组中
  6. ExtJs 备忘录(1)—— Form表单(一) [ 控件使用 ]
  7. 赣南师范学院数学竞赛培训第10套模拟试卷参考解答
  8. 明锐旅行车又大又便宜,值得买吗?
  9. Web项目--------原Oracle数据库的项目同时兼容MySql
  10. 4.软件架构设计:大型网站技术架构与业务架构融合之道 --- 操作系统
  11. 面试题-mysql优化
  12. wordpress登录美化css,wordpress后台login界面美化
  13. SIPp 安装及使用
  14. RealMedia Analyzer(mp4修复软件)v0.30绿色版
  15. 普华永道:AI到2030年将带动全球GDP增长14%,中国成最大受益国
  16. 清华大学计算机与科学系张荷花简历,清华大学软件学院
  17. 【M365运维】匹配用户UPN和Email地址
  18. Linux计划任务介绍
  19. 拼多多的店铺怎样引流和出价-纽黑文教学
  20. 不一般的Cover Letter

热门文章

  1. Android 常用开发框架
  2. 会员消费占比超过85%,或将成为“水果零售第一股”的百果园是怎样做到的?
  3. 搭建Gitlab教程详解
  4. Dbeaver做数据迁移
  5. JAVASE、JAVAEE、JAVAME介绍
  6. 如何在Java ME平台上获取手机串号
  7. URLConnection(三)
  8. b660主板和z690哪个好
  9. 用pandas处理数据过程记录
  10. 【塔望咨询】X【麦仕醇】开启精酿啤酒新纪元