2009-10-26 4 views
1

Je rencontre ce problème depuis un moment et je n'ai jamais vraiment réussi à le résoudre. Ce problème apparaît uniquement lorsque j'utilise les méthodes SendAsync/ReceiveAsync plutôt que les méthodes de socket Begin/EndSend pour les opérations asynchrones..Net Sockets -> throw System.InvalidOperationException

Si vous avez une bibliothèque de socket tcp assez sophistiquée et que vous vouliez remplacer les méthodes BeginSend par SendAsync, mais à cause du problème que je rencontre, j'ai toujours dû le remettre à plus tard. Mon serveur de socket gère des scénarios de stress intense avec> 1000 clients connectés en poussant constamment sur 100mbit/sec et je voudrais utiliser la méthode SendAsync pour ne pas avoir de surcharge d'allocation IAsyncResult. Quoi qu'il en soit, tout fonctionne bien tant que je ne fais qu'envoyer/recevoir des données, mais dans des situations de stress élevé lorsque le serveur tente de déconnecter/éteindre un client, je reçois occasionnellement l'exception suivante:

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: 

Je suis incapable d'attraper cette exception ne importe où il semble se produire dans le cadre .NET et je ne peux rien faire à ce sujet écraser mon serveur. Comme cela ne se produit que lorsque j'appelle ma procédure d'arrêt, je suppose que cela a quelque chose à voir avec l'appel de Shutdown sur le socket alors qu'il a encore une procédure de lecture/écriture en attente. Cependant, j'ai également essayé de retarder l'arrêt de l'appel jusqu'à ce que tous les appels Send/ReceiveAsync en lecture/écriture soient retournés et que j'aie appelé l'arrêt après cela mais cela n'a pas aidé non plus.

Voilà comment j'essaie de prises d'arrêt:

 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); 
               } 
              } 
             }); 
    } 

Répondre

2

Ok, pour une raison quelconque, il me aide toujours à poser des questions parce que je tends à comprendre les choses toujours peu de temps après:/

Il semble que asyncSendArgs.SetBuffer (null, 0, 0); est le coupable. Même si une autre partie du code doit s'assurer qu'il n'y a pas d'opérations asynchrones en attente avant que InternalDisconnect ne soit appelée, il semble qu'il y en a encore et que modifier le tampon alors qu'il est utilisé causerait certainement un problème. Je fais des tests de stress depuis 15 minutes et tout semble aller bien (avant que je reçoive cette exception en moins d'une minute). Je vais laisser courir plus longtemps et j'espère que ça l'a fait.

+1

Salut Tom Frey, Comment avez-vous résolu cette exception? Im maintenant faire face à cette exception –

Questions connexes