Я использую TcpClient с SslStream. В целом все работает нормально, но мы время от времени получаем журналы аварий. Кажется, это происходит из-за нестабильных сетевых подключений, и я, к сожалению, не могу воспроизвести его локально, несмотря на попытки создать «непредвиденные обстоятельства»:
- с использованием Fiddler для репликации очень медленного сетевого подключения
- уничтожение серверного приложения при отправке данных
- отключение сетевых кабелей
Ситуация такова:
Я называю BeginRead так:
_tcpClientStream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, pfnCallBack, null);
И тогда EndRead вызывается так:
iRx = _tcpClientStream.EndRead(asyn);
Единственное место, где используется iRx, - это скопировать полученные данные в новый массив:
var bytes = new byte[iRx];
Array.Copy(receiveBuffer, bytes, iRx);
В функции обратного вызова OnDataReceived я вызываю EndRead для SslStream, который выдает обработанное исключение:
Error in OnDataReceived System.IO.IOException: The read operation failed, see inner exception. ---> System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: size
at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
at System.Net.FixedSizeReader.StartReading()
at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
--- End of inner exception stack trace ---
at System.Net.Security._SslStream.EndRead(IAsyncResult asyncResult)
at System.Net.Security.SslStream.EndRead(IAsyncResult asyncResult)
at XXXXXXX.OnDataRecevied(IAsyncResult asyn)
Обычно это не проблема - это исключение перехватывается, и TcpClient закрывается и повторно запускается, чтобы попытаться восстановить соединение.
Однако в этом случае возникает второе исключение, которое генерируется одним из обработчиков ошибок UnhandledException:
AppDomain.CurrentDomain.UnhandledException
Current.DispatcherUnhandledException
Current.Dispatcher.UnhandledException
TaskScheduler.UnobservedTaskException
Эта трассировка стека выглядит так:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
Мы обрабатываем этот тип необработанной ошибки, чтобы показать пользователю сообщение о том, что произошла фатальная ошибка, и программное обеспечение должно закрыться.
Мои вопросы:
Кто-нибудь когда-либо видел эту ошибку раньше и смог воспроизвести точное исключение вне диапазона, которое я получаю? Несмотря на мои попытки воссоздать проблему (используя методы, описанные выше), я не могу воссоздать исключение, это всегда более стандартное исключение Socket IO:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.Security._SslStream.EndRead(IAsyncResult asyncResult)
at System.Net.Security.SslStream.EndRead(IAsyncResult asyncResult)
at XXXXXXXXX.OnDataRecevied(IAsyncResult asyn)
Можно ли как-то обработать это исключение в моем коде Socket или оно всегда будет появляться в одном из этих событий UnhandledException? Если так, то каков наилучший способ справиться с этим? В основном мне нужна логика в обработчике событий, чтобы определить, что программное обеспечение не должно закрываться, если получена эта конкретная ошибка?