From 841f1892d4efc16d03ccfffcb544a6eca9927b59 Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Mon, 3 Nov 2025 13:12:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=A5=E6=94=B6=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E5=A4=9A=E7=BA=BF=E7=A8=8B=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IRC.Core.SCP/Program.cs | 4 + IRC.Core.SCP/Service/CStoreSCPService.cs | 106 +++++++++++++++------ IRC.Core.SCP/appsettings.Test_HIR_SCP.json | 2 + 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/IRC.Core.SCP/Program.cs b/IRC.Core.SCP/Program.cs index 4f34632f7..e6278b35d 100644 --- a/IRC.Core.SCP/Program.cs +++ b/IRC.Core.SCP/Program.cs @@ -14,6 +14,7 @@ using MassTransit; using MassTransit.NewIdProviders; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Identity.Client; using Panda.DynamicWebApi; using Serilog; using Serilog.Events; @@ -218,6 +219,9 @@ else DicomSetupBuilder.UseServiceProvider(app.Services); +// Program.cs +IRCAppConfig.Configuration = builder.Configuration; + var logger = app.Services.GetService>(); diff --git a/IRC.Core.SCP/Service/CStoreSCPService.cs b/IRC.Core.SCP/Service/CStoreSCPService.cs index ef885febd..4bd81d5b9 100644 --- a/IRC.Core.SCP/Service/CStoreSCPService.cs +++ b/IRC.Core.SCP/Service/CStoreSCPService.cs @@ -28,6 +28,7 @@ using FellowOakDicom.IO.Buffer; using System.Diagnostics.CodeAnalysis; using FellowOakDicom.Network.Client; using MassTransit.Futures.Contracts; +using Microsoft.Identity.Client; namespace IRaCIS.Core.SCP.Service { @@ -36,6 +37,10 @@ namespace IRaCIS.Core.SCP.Service { public bool IsSupportThirdService { get; set; } + public bool IsForwardImageMultiThread { get; set; } + + + public List CalledAEList { get; set; } public string ServerPort { get; set; } @@ -50,6 +55,11 @@ namespace IRaCIS.Core.SCP.Service public string IP { get; set; } } + public static class IRCAppConfig + { + public static IConfiguration Configuration { get; set; } + } + @@ -77,6 +87,8 @@ namespace IRaCIS.Core.SCP.Service private List ThirdDestinationAEList { get; set; } + + private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[] { DicomTransferSyntax.ExplicitVRLittleEndian, @@ -103,6 +115,22 @@ namespace IRaCIS.Core.SCP.Service DicomTransferSyntax.ImplicitVRLittleEndian }; + // 定义一个静态信号量,控制同时最多 N 个转发线程 + + private static SemaphoreSlim _forwardLimiter; + + // ✅ 静态构造函数(只执行一次,全局初始化) + static CStoreSCPService() + { + // 默认单线程 + + var maxThreads = IRCAppConfig.Configuration.GetValue("DicomSCPServiceConfig:MultiThreadCount", 1); + + _forwardLimiter = new SemaphoreSlim(maxThreads); + + Log.Logger.Information($"初始化 DICOM 转发线程限制为: {maxThreads}"); + } + public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider) : base(stream, fallbackEncoding, log, dependencies) @@ -306,6 +334,43 @@ namespace IRaCIS.Core.SCP.Service } + private async Task ForwardToThirdPartyAsync(DicomCStoreRequest request, ThirdDestinationAE findDestination) + { + await _forwardLimiter.WaitAsync(); // 限制并发数量 + try + { + var forwardRequest = new DicomCStoreRequest(request.File.Clone()); + + var client = DicomClientFactory.Create( + findDestination.IP, + findDestination.Port, + false, + DicomSCPServiceConfig.CalledAEList.First(), + findDestination.Name); + + DicomStatus finalStatus = DicomStatus.Success; + + forwardRequest.OnResponseReceived += (rq, rp) => + { + Log.Logger.Information($"Forwarded C-STORE Response: {rq.SOPInstanceUID} {rp.Status}"); + finalStatus = rp.Status; // 记录目标 PACS 返回状态 + }; + + await client.AddRequestAsync(forwardRequest); + await client.SendAsync(); + + return finalStatus; // 返回实际状态 + } + catch (Exception ex) + { + Log.Logger.Error("Error forwarding C-STORE: " + ex.Message); + return DicomStatus.ProcessingFailure; // 出错返回失败状态 + } + finally + { + _forwardLimiter.Release(); + } + } public async Task OnCStoreRequestAsync(DicomCStoreRequest request) @@ -336,37 +401,24 @@ namespace IRaCIS.Core.SCP.Service { _isCurrentThirdForward = true; - _ = Task.Run(async () => + var findDestination = ThirdDestinationAEList.FirstOrDefault(t => t.Name == cmoveInfo.DestinationAE); + + if (DicomSCPServiceConfig.IsForwardImageMultiThread) { + // 多线程模式,异步执行 + _ = Task.Run(() => ForwardToThirdPartyAsync(request, findDestination)); - try - { - var findDestination = ThirdDestinationAEList.FirstOrDefault(t => t.Name == cmoveInfo.DestinationAE); + // 立即返回 Success + return new DicomCStoreResponse(request, DicomStatus.Success); + } + else + { + // 单线程模式,同步等待完成 + var responseStatus = await ForwardToThirdPartyAsync(request, findDestination); - var forwardRequest = new DicomCStoreRequest(request.File.Clone()); + return new DicomCStoreResponse(request, responseStatus); + } - // 创建客户端连接到目标 PACS - var client = DicomClientFactory.Create(findDestination.IP, findDestination.Port, false, DicomSCPServiceConfig.CalledAEList.First(), cmoveInfo.DestinationAE); - - // 可以加入 OnResponseReceived 来处理目标 PACS 返回状态 - forwardRequest.OnResponseReceived += (rq, rp) => - { - Log.Logger.Information($"Forwarded C-STORE Response: {rq.SOPInstanceUID} {rp.Status}"); - - }; - - await client.AddRequestAsync(forwardRequest); - await client.SendAsync(); - } - catch (Exception ex) - { - Log.Logger.Error("Error forwarding C-STORE: " + ex.Message); - } - - }); - - // 立即返回 Success 给原发送方 - return new DicomCStoreResponse(request, DicomStatus.Success); } } diff --git a/IRC.Core.SCP/appsettings.Test_HIR_SCP.json b/IRC.Core.SCP/appsettings.Test_HIR_SCP.json index 7fa247e33..5dcf97a76 100644 --- a/IRC.Core.SCP/appsettings.Test_HIR_SCP.json +++ b/IRC.Core.SCP/appsettings.Test_HIR_SCP.json @@ -25,6 +25,8 @@ }, "DicomSCPServiceConfig": { "IsSupportThirdService": true, + "IsForwardImageMultiThread": true, + "MultiThreadCount":10, "CalledAEList": [ "HIRAE", "STORESCP"