
本文详解 pynetdicom 中 Modality Worklist(MWL)SCP 的正确实现方式,重点纠正“仅返回 SUCCESS 状态而无实际数据”的常见错误,强调必须使用 0xFF00(PENDING)状态逐条返回匹配数据集,并以 0x0000(SUCCESS)作为终结响应。
本文详解 pynetdicom 中 modality worklist(mwl)scp 的正确实现方式,重点纠正“仅返回 success 状态而无实际数据”的常见错误,强调必须使用 `0xff00`(pending)状态逐条返回匹配数据集,并以 `0x0000`(success)作为终结响应。
在 DICOM 工作列表(Modality Worklist, MWL)服务中,SCP(Service Class Provider)需严格遵循 C-FIND 协议语义:查询响应不是单次返回一个 SUCCESS 状态加数据,而是先多次返回 PENDING (0xFF00) 状态并附带匹配的患者/检查数据集,最后以无数据的 SUCCESS (0x0000) 结束整个响应序列。若仅 yield (0x0000, identifier),则 DICOM 标准将其解释为“查询成功但无匹配结果”,导致 SCU(如 miele-wl-scu)无法解析出任何工作列表项。
以下是修正后的完整可运行示例(基于 pynetdicom v2.0+):
import pydicom
from pydicom.dataset import Dataset
from pydicom.uid import ExplicitVRLittleEndian
from pynetdicom import AE, evt, debug_logger
from pynetdicom.sop_class import ModalityWorklistInformationFind
debug_logger()
def on_c_find(event):
"""Handle C-FIND request for Modality Worklist."""
# 获取请求中的查询数据集(可用于过滤)
req_dataset = event.identifier
# 构造一个模拟的匹配工作列表项(实际应用中应从数据库/配置中查询)
ds = Dataset()
ds.PatientName = "Doe^John"
ds.PatientID = "123456"
ds.PatientBirthDate = "19800101"
ds.PatientSex = "M"
ds.AccessionNumber = "ACC123456789"
ds.StudyInstanceUID = "1.2.3.4.5.6.7.8.9.10"
ds.RequestedProcedureDescription = "Chest PA and Lateral"
ds.RequestedProcedureID = "REQ001"
# 必须设置传输语法属性(MWL 要求显式 VR 小端序)
ds.is_little_endian = True
ds.is_implicit_VR = False # ⚠️ 关键:MWL 必须使用显式 VR
ds.file_meta = pydicom.Dataset()
ds.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
# 返回 PENDING 状态 + 数据集(表示有匹配项)
yield (0xFF00, ds) # ✅ 正确:每条记录用 0xFF00
# 可选:再返回一条(模拟多条工作项)
ds2 = ds.copy()
ds2.PatientName = "Smith^Jane"
ds2.AccessionNumber = "ACC987654321"
ds2.RequestedProcedureDescription = "Abdominal Ultrasound"
yield (0xFF00, ds2)
# 最终返回 SUCCESS(无数据集),标志响应结束
yield (0x0000, None) # ✅ 正确:终结响应不带数据
def main():
ae = AE()
ae.add_supported_context(ModalityWorklistInformationFind)
ae.add_supported_context("1.2.840.10008.1.1") # Verification SOP Class
handlers = [(evt.EVT_C_FIND, on_c_find)]
print("✅ DICOM MWL SCP started on localhost:11112")
ae.start_server(("localhost", 11112), evt_handlers=handlers)
if __name__ == "__main__":
main()
关键注意事项:
- ✅ 状态码语义不可混淆:0xFF00(PENDING)用于携带有效数据集;0x0000(SUCCESS)必须且只能在最后、不带数据集时发出;
- ✅ 显式 VR 强制要求:DICOM MWL 标准规定传输语法必须为 ExplicitVRLittleEndian(UID 1.2.840.10008.1.2.1),因此 is_implicit_VR = False 是必需的;
- ✅ 数据集完整性:至少需包含 PatientName、PatientID、AccessionNumber、RequestedProcedureDescription 等核心字段,否则部分 SCU(如 Miele)可能忽略该条目;
- ⚠️ 避免空响应陷阱:若查询无匹配结果,仍需返回 yield (0x0000, None),而非不 yield 任何内容,否则 SCU 可能超时挂起;
- ? 调试建议:启用 debug_logger() 后观察日志中 C-FIND RSP 的 status 字段和 dataset presence,确认是否按 0xFF00 → 0xFF00 → ... → 0x0000 顺序发送。
遵循上述规范,即可确保 MWL SCU(如 miele-wl-scu、dcm4chee-wl 或飞利浦/西门子设备)正确接收并解析工作列表项,彻底解决“只返回 SUCCESS 却无数据”的问题。










