У меня уже давно есть эта проблема, и я так и не смог ее решить. Эта проблема возникает только при использовании методов SendAsync / ReceiveAsync, а не методов сокетов Begin / EndSend для асинхронных операций.
Если у вас довольно сложная библиотека сокетов tcp и вы хотели заменить методы BeginSend на SendAsync, но из-за проблемы, с которой я столкнулся, мне всегда приходилось ее откладывать. Мой сокет-сервер обрабатывает тяжелые стрессовые сценарии с более чем 1000 подключенными клиентами, которые постоянно работают со скоростью более 100 Мбит / с, и я хотел бы использовать метод SendAsync, чтобы у меня не было накладных расходов на распределение IAsyncResult.
В любом случае, что происходит, все работает нормально, пока я просто отправляю / получаю данные, однако в сценариях с высокой нагрузкой, когда сервер пытается отключить / выключить клиент, я иногда получаю следующее исключение:
System.InvalidOperationException was unhandled
Message=Cannot apply a context that has been marshaled across AppDomains, that was not acquired through a Capture operation or that has already been the argument to a Set call.
Source=mscorlib
StackTrace:
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
at System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
InnerException:
Я не могу поймать это исключение в любом месте, так как оно, похоже, происходит в .NET Framework, и я ничего не могу поделать, если мой сервер рухнет.
Поскольку это происходит только тогда, когда я вызываю свою процедуру завершения работы, я предполагаю, что это как-то связано с вызовом Shutdown для сокета, пока у него все еще есть процедура чтения / записи.
Однако я также пытался отложить отключение вызова до тех пор, пока не будут возвращены все вызовы «чтение / запись» Send / ReceiveAsync и отключение вызова после этого, но это тоже не помогло.
Вот как я пытаюсь отключить сокеты:
private void InternalDisconnect(SocketError socketError)
{
lock (shutdownLock)
{
if (isShutdown)
return;
isShutdown = true;
}
allowSend = false;
SocketError = socketError;
ThreadPool.QueueUserWorkItem(delegate
{
lock (padLock)
{
try
{
if (TcpSocketStatus == TcpSocketStatus.Disconnected)
return;
TcpSocketStatus = TcpSocketStatus.Disconnecting;
if (asyncSendArgs != null)
{
asyncSendArgs.Completed -= SendCompleted;
asyncSendArgs.SetBuffer(null, 0, 0);
asyncSendArgs.Dispose();
}
if (asyncReceiveArgs != null)
{
asyncReceiveArgs.Completed -= ReceiveCompleted;
asyncReceiveArgs.SetBuffer(null, 0, 0);
asyncReceiveArgs.Dispose();
}
try
{
bufferedSender.Clear();
Socket.Shutdown(SocketShutdown.Both);
if (Socket.Connected)
{
Socket.Disconnect(true);
}
}
catch
{
}
try
{
Socket.Close();
}
catch
{
}
TcpSocketStatus = TcpSocketStatus.Disconnected;
if (socketError != SocketError.Success)
{
if (log.IsDebugEnabled)
log.Debug("SocketDisconnected\tSocketError:{0}", socketError);
}
else
{
if (log.IsDebugEnabled)
log.Debug("SocketDisconnected");
}
DisconnectTime = DateTime.UtcNow;
if (TcpSocketDisconnected != null)
TcpSocketDisconnected(this);
}
catch (Exception ex)
{
log.ErrorException("InternalDisconnect", ex);
}
}
});
}