web-dev-qa-db-fra.com

La connexion de socket a été interrompue - CommunicationException

Initialement:

  • Je pensais que c'était un problème de référence circulaire….
  • Le problème était lié à l'absence de configuration des configurations de service.
  • Étant donné que les valeurs par défaut sont très basses, l'envoi d'un grand nombre de données entraînera l'effondrement du service.

Scénario:

  • Il semble que mon service WCF ait des références circulaires, mais l'utilisation de "[DataContract (IsReference = true)]" ne résout en rien le problème.
  • Je reçois le message d'erreur "La connexion de socket a été interrompue. Cela peut être dû à une erreur de traitement de votre message ou au dépassement du délai de réception par l'hôte distant, ou à un problème de ressources réseau sous-jacent. Le délai d'expiration du socket local était" 00: 01: 00 " . "
  • Ai-je raté quelque chose?

Code:

[DataContract(IsReference=true)]
public class Message
{
    [DataMember]
    public string TopicName { get; set; }

    [DataMember]
    public string EventData { get; set; }

    [DataMember]
    public SerializableDictionary<string, FuturesLineAsset> FuturesLineDictionary { get; set ; }
}

Pensées:

  • Je me demande si c'est parce que j'ai une classe FuturesAsset, qui a une propriété de type BindableDictionary (THIS IS UN OBJET CUSTOM), et que cette propriété contient une liste de FuturesLinesAssets.
  • Voir ci-dessous:

Parent:

public class FuturesAsset
{
    public string AssetName { get; set; }
    public BindableDictionary<string, FuturesLineAsset> AssetLines { get; private set; }

    public FuturesAsset()
    {
        AssetLines = new BindableDictionary<string, FuturesLineAsset>();
    }

    public FuturesAsset(string assetName)
    {
        AssetLines = new BindableDictionary<string, FuturesLineAsset>();
        AssetName = assetName;
    }
}

Enfant:

public class FuturesLineAsset
{

    public string ReferenceAsset { get; set; }
    public string MID { get; set; }
    public double LivePrice { get; set; }
    public DateTime UpdateTime { get; set; }
    public DateTime LastContributedTime { get; set; }
    public double Spread { get; set; }
    public double Correlation { get; set; }
    public DateTime Maturity { get; set; }
    public double ReferenceCurve { get; set; }

    public FuturesLineAsset(string mID, string referenceAsset, double livePrice)
    {
        MID = mID;
        ReferenceAsset = referenceAsset;
        ReutersLivePrice = livePrice;
    }
}
21
Goober

cette exception n'est pas liée à la référence circulaire, elle consiste simplement en un dépassement de délai lorsque vous essayez de transférer des tonnes de données sur le réseau.

Les valeurs par défaut fournies avec WCF sont très faibles (elles ont été modifiées dans WCF 4, je crois). Lisez ces deux articles sur le blog, ils devraient vous donner une idée de la façon de détrôner votre service:

Création de services WCF hautes performances

Comment étrangler un service Wcf, aider à prévenir les attaques par déni de service et maintenir l'évolutivité Wcf

Update: il existe également un certain nombre de délais d'attente différents dans la configuration de WCF et selon que vous parliez du client ou du serveur dont vous parlez, vous devez mettre à jour une clause de délai d'attente différente ... lisez ceci thread sur ce que chacun signifie et vous devriez être capable de trouver celui que vous avez besoin de croiser. Ou, vous pouvez simplement définir chaque délai d'attente sur int.max si vous ne vous souciez pas vraiment de savoir si un appel peut prendre un peu de temps.

12
theburningmonk

Cette erreur peut être causée par un certain nombre de choses. Bien qu’il s’agisse d’un problème de minutage dans ce cas, cela n’a généralement rien à voir avec les minutages, surtout si l’erreur est reçue immédiatement . Les raisons possibles sont:

  • Les objets utilisés en tant que paramètres ou types de retour dans votre contrat n'ont pas de constructeur sans paramètre et ne sont pas décorés avec l'attribut DataContract. Vérifiez les classes utilisées en tant que paramètres ou types de retour, mais également tous les types utilisés par les propriétés publiques de ces classes. Si vous implémentez un constructeur avec des paramètres pour l'une de ces classes, le compilateur n'ajoutera plus le constructeur sans paramètre par défaut pour vous, vous devrez donc l'ajouter vous-même.
  • Les limites par défaut définies dans la configuration du service sont trop basses (MaxItemsInObjectGraph, MaxReceivedMessageSize, MaxBufferPoolSize, MaxBufferSize, MaxArrayLength).
  • Certaines propriétés publiques de vos objets DataContract sont en lecture seule. Assurez-vous que toutes les propriétés publiques ont à la fois des accesseurs et des setters.
16
Adrian T

Ce problème est dû à un long processus d'initialisation appelé à partir de l'événement OnStart d'un programme d'installation de l'hôte de service Windows. Fixé en définissant le mode de sécurité et les délais d'attente pour la liaison TCP.

            // Create a channel factory.
            NetTcpBinding b = new NetTcpBinding();
            b.Security.Mode = SecurityMode.Transport;
            b.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
            b.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;

            b.MaxReceivedMessageSize = 1000000;
            b.OpenTimeout = TimeSpan.FromMinutes(2);
            b.SendTimeout = TimeSpan.FromMinutes(2);
            b.ReceiveTimeout = TimeSpan.FromMinutes(10);
3
Adrian Holmes

Ce problème peut également être dû au fait de ne pas nettoyer le client WCF lorsque vous avez fini de l’utiliser. Dans notre système, nous utilisons le modèle à usage unique en incorporant tous les appels de fonction dans le système pour permettre un nettoyage et une journalisation appropriés. Nous utilisons une version de la classe suivante:

    public class WcfWrapper : IDisposable
    {
        private readonly OperationContextScope _operationContextScope;
        private readonly IClientChannel _clientChannel;

        public WcfWrapper(IClientChannel clientChannel)
        {
            _clientChannel = clientChannel;
            _operationContextScope = new OperationContextScope(_clientChannel);
        }



        public void Dispose()
        {
            _operationContextScope.Dispose();
        }


        public T Function<T>(Func<T> func)
        {
            try
            {
                var result = func();
                _clientChannel.Close();
                return result;
            }
            catch (Exception ex)
            {
                KTrace.Error(ex);
                _clientChannel.Abort();
                throw;
            }

        }

        public void Procedure(Action action)
        {
            try
            {
                action();
                _clientChannel.Close();
            }
            catch (Exception ex)
            {
                KTrace.Error(ex);
                _clientChannel.Abort();
                throw;
            }
        }
    }

}

Chaque appel WCF que nous passons dans notre service passe par une classe d'interface définie comme celle-ci:

    public sealed class WcfLoginManager : ILoginManager
    {
        private static LoginManagerClient GetWcfClient()
        {
            return 
                new LoginManagerClient(
                    WcfBindingHelper.GetBinding(),
                    WcfBindingHelper.GetEndpointAddress(ServiceUrls.LoginManagerUri));

        }

        public LoginResponse Login(LoginRequest request)
        {
            using(var loginManagerClient = GetWcfClient())
            using (var slice = new WcfWrapper(loginManagerClient.InnerChannel))
            {
                DSTicket ticket;
                DSAccount account;
                return slice.Function(() => new LoginResponse(loginManagerClient.Login(request.accountName, request.credentials, out ticket, out account), ticket, account));
            }
        }
    }

En utilisant ce modèle, tous les appels WCF dans le système sont encapsulés avec la méthode Function ou la méthode Procedure, ce qui leur permet de s’assurer d’abord de la consignation de toutes les erreurs et ensuite de s’assurer que le canal est fermé si aucune erreur ne se produit mais annulé si une exception se produit . Enfin, comme dans une déclaration using, la disposition finale du canal est appelée. De cette manière, les erreurs dues à des canaux non nettoyés, ressemblant à cette erreur, seront évitées.

2
Jon Ediger

Cette exception s'est produite pour moi lorsque je renvoyais un objet contenant des collections IEnumerable, et une exception s'est produite lors de l'extraction de l'un des membres de la collection. À ce stade, il est trop tard pour le récupérer dans votre code et WCF est supposé conçu pour déconnecter le socket dans ce cas, car il est également trop tardif pour signaler une exception au client, car les résultats de la diffusion en continu ont déjà commencé.

1
AndyH

L'erreur WCF:

La connexion de socket a été interrompue. Cela pourrait être dû à une erreur traitement de votre message ou dépassement du délai de réception par le hôte distant ou un problème de ressource réseau sous-jacent. Prise locale le timeout était ...

où les délais signalés sont très proches de 1 minute (par exemple 00:00:59.9680000) ou 1 minute exactement (c'est-à-dire 00:01:00) peuvent être causés par un message trop volumineux et un dépassant les paramètres de la liaison .

Cela peut être corrigé en augmentant les valeurs dans le fichier de configuration, par exemple:

<binding name="MyWcfBinding" 
         maxReceivedMessageSize="10000000" 
         maxBufferSize="10000000" 
         maxBufferPoolSize="10000000" />

(à titre d’exemple, vous voudrez peut-être les ajuster).

0
SharpC