仅在发送大请求时使用 .NET 5 时出现 SocketException (10054)
Posted
技术标签:
【中文标题】仅在发送大请求时使用 .NET 5 时出现 SocketException (10054)【英文标题】:SocketException (10054) while using .NET 5 only when large request is sent 【发布时间】:2021-12-08 06:52:00 【问题描述】:我正在将我的 WCF 客户端从 .NET Framework 4.6.1 迁移到 .NET 5,并且每次发送大请求(如 500KB)时都会遇到 SocketException。您可以在下面找到异常、服务器配置、.NET Framework 配置和 .NET 5 配置。
例外:
System.ServiceModel.CommunicationException: Error while copying content to a stream.
---> System.Net.Http.HttpRequestException: Error while copying content to a stream.
---> System.IO.IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host..
---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
--- End of inner exception stack trace ---
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Security.SslStream.<WriteSingleChunk>g__CompleteWriteAsync|177_1[TIOAdapter](ValueTask writeTask, Byte[] bufferToReturn)
at System.Net.Security.SslStream.WriteAsyncChunked[TIOAdapter](TIOAdapter writeAdapter, ReadOnlyMemory`1 buffer)
at System.Net.Security.SslStream.WriteAsyncInternal[TIOAdapter](TIOAdapter writeAdapter, ReadOnlyMemory`1 buffer)
at System.Net.Http.HttpConnection.WriteAsync(ReadOnlyMemory`1 source, Boolean async)
at System.ServiceModel.Channels.BufferedMessageContent.SerializeToStreamAsync(Stream stream, TransportContext context)
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
--- End of inner exception stack trace ---
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendRequestContentWithExpect100ContinueAsync(HttpRequestMessage request, Task`1 allowExpect100ToContinueTask, HttpContentWriteStream stream, Timer expect100Timer, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, Boolean async, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, Boolean async, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
--- End of inner exception stack trace ---
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass1_0.<CreateGenericTask>b__0(IAsyncResult asyncResult)
--- End of stack trace from previous location ---
at EQ.SP.SOS.Adapter.Application.Services.AlertsService.GetUnreadAlertsAsync() in C:\Repozytoria\ShareholderPlatform\APP\EQ.SP.SOS.Adapter\EQ.SP.SOS.Adapter.Application\Services\AlertsService.cs:line 53
at EQ.SP.SOS.Adapter.API.Controllers.AlertsController.GetUnreadAlerts() in C:\Repozytoria\ShareholderPlatform\APP\EQ.SP.SOS.Adapter\EQ.SP.SOS.Adapter.API\Controllers\AlertsController.cs:line 26
at lambda_method537(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at EQ.SP.SOS.Adapter.API.Middleware.RequestTransferAgentMiddleware.Invoke(HttpContext context, ITransferAgentContext transferAgentContext) in C:\Repozytoria\ShareholderPlatform\APP\EQ.SP.SOS.Adapter\EQ.SP.SOS.Adapter.API\Middleware\RequestTransferAgentMiddleware.cs:line 22
at EQ.SP.SOS.Adapter.API.Middleware.RequestMetaDataMiddleware.Invoke(HttpContext context, IMetaDataContext metadataContext, IConfiguration config) in C:\Repozytoria\ShareholderPlatform\APP\EQ.SP.SOS.Adapter\EQ.SP.SOS.Adapter.API\Middleware\RequestMetaDataMiddleware.cs:line 22
at EQ.SP.SOS.Adapter.API.Middleware.RequestUserDataMiddleware.Invoke(HttpContext context, IUserDataContext userDataContext, IConfiguration config) in C:\Repozytoria\ShareholderPlatform\APP\EQ.SP.SOS.Adapter\EQ.SP.SOS.Adapter.API\Middleware\RequestUserMiddleware.cs:line 24
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
服务器配置:
<wsHttpBinding>
<binding name="wsbinding" closeTimeout="10:01:00" openTimeout="10:01:00" receiveTimeout="10:10:00" sendTimeout="10:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="false" allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
<wsHttpBinding>
.NET Framework 4.6.1 client config:
<wsHttpBinding>
<binding name="wsbinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
.NET 5 客户端配置:
private static void RegisterWcfClient<TIService, TClient>(this IServiceCollection services, string baseUrl,
string serviceName, string certName, string storeLocation)
where TIService : class
where TClient : ClientBase<TIService>, new()
services.AddScoped(servicesCollection =>
var client = new TClient();
var customBinding = new CustomBinding();
var httpsBindingElement = new HttpsTransportBindingElement
AllowCookies = true,
MaxBufferSize = int.MaxValue,
MaxReceivedMessageSize = int.MaxValue,
RequireClientCertificate = true
;
customBinding.Elements.Add(httpsBindingElement);
client.Endpoint.Binding = customBinding;
client.Endpoint.Address = new EndpointAddress($"baseUrl/serviceName");
var storeLocationEnum = ToStoreLocationEnum(storeLocation);
client.ClientCredentials.ClientCertificate.SetCertificate(storeLocationEnum, StoreName.My,
X509FindType.FindBySubjectName, certName);
return client;
);
services.AddScoped(servicesCollection =>
var factory = servicesCollection.GetService<TClient>()?.ChannelFactory;
return factory.CreateChannel();
);
.NET 5 替代配置:
private static void RegisterWcfClient<TIService, TClient>(this IServiceCollection services, string baseUrl,
string serviceName, string certName, string storeLocation)
where TIService : class
where TClient : ClientBase<TIService>, new()
services.AddScoped(servicesCollection =>
var client = new TClient();
var customBinding = new WSHttpBinding(SecurityMode.Transport, false);
customBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
customBinding.ReaderQuotas.MaxDepth = 2147483647;
customBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
customBinding.ReaderQuotas.MaxArrayLength = 2147483647;
customBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;
customBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
customBinding.CloseTimeout = new TimeSpan(0, 10, 0);
customBinding.OpenTimeout = new TimeSpan(0, 10, 0);
customBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
customBinding.SendTimeout = new TimeSpan(0, 10, 0);
customBinding.BypassProxyOnLocal = false;
customBinding.TransactionFlow = false;
customBinding.MaxBufferPoolSize = 2147483647;
customBinding.MaxReceivedMessageSize = 2147483647;
customBinding.TextEncoding = Encoding.UTF8;
customBinding.UseDefaultWebProxy = true;
customBinding.AllowCookies = false;
customBinding.ReliableSession.Ordered = true;
customBinding.ReliableSession.InactivityTimeout = new TimeSpan(0, 10, 0);
client.Endpoint.Binding = customBinding;
client.Endpoint.Address = new EndpointAddress($"baseUrl/serviceName");
var storeLocationEnum = ToStoreLocationEnum(storeLocation);
client.ClientCredentials.ClientCertificate.SetCertificate(storeLocationEnum, StoreName.My,
X509FindType.FindBySubjectName, certName);
return client;
);
services.AddScoped(servicesCollection =>
var factory = servicesCollection.GetService<TClient>()?.ChannelFactory;
return factory.CreateChannel();
);
它适用于小请求,但对于较大的请求,我会提到异常。 我根据我在 .NET 5 中的配置从头开始创建了 .NET 4.6.1 WCF 客户端,并且在 .NET 4.6.1 上一切正常。 关于异常 - 我第一次发送请求时,错误出现需要 20 秒。对于下一个请求,它的速度要快得多(比如 1-2 秒)。
到目前为止我的调查:
在官方 WCF repo https://github.com/dotnet/wcf/issues/4751 上创建问题 在服务器上禁用证书吊销检查但没有成功 检查了事件查看器和 PerfView 是否有任何相关异常,但没有发现任何异常 尝试修改 HTTP 请求上的 Connection 标头,但没有成功我不知道这个错误的根本原因是什么。这似乎是一个服务器端问题,但为什么它在 .NET 4.6.1 客户端上运行良好?
知道那里可能出了什么问题吗?
【问题讨论】:
【参考方案1】:您的错误是:System.ServiceModel.CommunicationException:将内容复制到流时发生错误。 可能的原因是主机已经到了空闲超时时间,启动时间过长。由于代码或设计问题,主机可能会意外重启。
【讨论】:
这更适合作为对问题的评论。以上是关于仅在发送大请求时使用 .NET 5 时出现 SocketException (10054)的主要内容,如果未能解决你的问题,请参考以下文章
从 Angular 向 Asp.net 发送 post 请求时出现错误 405
向 ASP.NET Web API 发送请求时出现 CORS 错误