IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MFC Discussion :

CSocket ne reçoit plus de notification de réception


Sujet :

MFC

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Octobre 2008
    Messages : 179
    Par défaut CSocket ne reçoit plus de notification de réception
    Bonjour,

    mon problème a déjà été évoqué, mais la réponse était généralement incomplète ou inadaptée (ou incompréhensive parfois).
    Je la reformule donc à ma sauce, en espérant y trouver une réponse.

    Pour le résumer : le socket ouvert par mon serveur pour gérer la connection à un client reçoit pendant un certain temps des notifications de données disponibles (ie intervention de CSocket::OnReceive()), puis soudainement cesse de recevoir ces notifications. Si j'interviens à ce moment là et que je force par l'appel de 'CSocket::Receive(...,....) la réception, les notifications reprennent, jusqu'à cesser à nouveau un peu plus tard.

    Etant donné que ça me semble être un problème de fond (mauvaise compréhension des sockets MFC en tête de mes suppositions), je ne poste pas le code correspondant ici. A votre demande, je le ferai.
    Pour clarté, je décris mon application plus-bas.

    Est-ce que vous avez une idée du problème ici?
    Est-ce qu'il existe en particulier un moyen "propre" de relancer la machine des notifications sans passer par une rustine inesthétique?

    -------------------------------------------------------------------

    PS : Je précise pour info que lorsque je n'attends pas de confirmation du client ça fonctionne bien (communication à sens unique en somme)... jusqu'à ce que je déborde la pile du client. D'où la raison des messages de confirmation.


    Une petite description de mes applis :

    Mes applications sont de type CLient/Serveur sur protocole TCP (mode connecté "STREAM", sur couche réseau wifi ad-hoc).

    Le client est installé sur un Mac et fonctionne parfaitement (à mon goût en tous cas). Bien qu'adapté pour l'émission et la réception, il est avant tout un récepteur de données (données de gros volumes : plusieurs 100kO)

    le Serveur est installé sur un PC (Windows XP SP2). L'application (View Based) est développée sous Visual Studio 6 et l'API utilisée pour les sockets est celle fournie dans les MFC : CSocket.

    Les données sont échangées sous forme de chaînes d'octets, et des interpréteurs des 2 côtés les traitent jusqu'à présent toujours avec succès (réglant entre autre tous les pbs d'endian).

    L'échange des données se passe de la façon suivante :
    Le client envoie quand ça lui chante des messages textes, que la fonction "OnReceive" de mon Socket Serveur traite en temps "réel".
    Le Serveur envoie initialement un gros paquet de données à traiter puis cesse tout envoie tant qu'il n'a pas reçu de confirmation du client ; le Client de son côté le reçoit, puis envoie une confirmation (message prédéfini) au serveur. Le Serveur continue néanmoins à traiter les messages reçus pendant ce temps (c'est dans ce traitement qu'il identifie la confirmation). Par la suite, le serveur envoie un nouveau gros paquet de données dès qu'il reçoit confirmation de la réception du précédent paquet.

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 492
    Par défaut
    TCP, c'est pas terrible pour faire des notifications.
    Vérifiez avec un sniffer réseaux si le problème n'est pas plutôt liée à la configuration de TCP à niveau de la bufferisation coté client.

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Octobre 2008
    Messages : 179
    Par défaut
    Avant de me lancer dans un reniflage de réseau - pas par paresse* mais parceque je n'ai encore jamais fait celà- je veux être sûr de comprendre le pourquoi...

    Un problème de bufferisation, je suppose que ça veut dire que les données côté Client sont accumulées sans être jamais être envoyées, c'est bien celà?
    Si il y avait un tel problème, l'appel de Receive() forcerait le client à vider sa pile du nombre d'octets demandés?

    Par ailleurs,
    TCP, c'est pas terrible pour faire des notifications.
    .
    Est-ce qu'on parle bien des mêmes notifications ici : je parle pour ma part des messages windows qui déclenchent l'appel de OnReceive(). Mes "confirmations" sont des notifications, dans un sens, mais ce sont bien les notifications windows qui cessent (et du même coup, je ne reçois plus aucune confirmation sauf si je force la lecture avec Receive()).

    Donc si je dois renifler le réseau client, l'idéal est de le faire lorsque je tombe en panne de notifications, afin de confirmer que les messages sont empilés côté Mac et pas perdus en cours de route?


    * : Du reste je viens de passer 30 minutes à essayer d'installer wireshark sur le Mac, et ce n'est pas gagné pour réussir à le faire tourner.

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 492
    Par défaut
    Vous pouvez renifler aussi bien sur le serveur que sur le client.
    Le but est de voir comment les données sont transférées entre eux, pas de voir d'éventuels problème réseaux.

    Il est préférable de voir le trafic avant, pendant et après l'incident pour pouvoir les comparer.

    Votre interprétation du terme bufferisation correspond à la mienne.

    TCP est un protocole de type flux qui se prête mal à une sémantique de notification, doit votre eventuel problème de notification.

    TCP contient des mécanismes de gestion de flux, pourquoi ne pas s'en servire ?

    Si c'est pour implémenter un mécanisme de request/response à la HTTP, il faut attendre la réponse à la fin de chaque demande, et configurer la connexion pour ne pas faire de bufferisation pour fait un Keep-alive à la HTTP.

    Avec le trafic réseau, on pourra vérifier si le problème et au niveau de la communication entre le client et le serveur ou s'il est dans le code du serveur.

  5. #5
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Octobre 2008
    Messages : 179
    Par défaut
    Bon,

    je patauge un petit peu dans la manipulation du renifleur, et dois de plus me plonger dans une couche que j'espérais garder transparence. Au moins je me coucherai moins bête.

    Bien que je n'ai pas fini mon analyse, je poste déjà le résultat du renifleur sur un test.

    Le test réalisé est le suivant :

    • Serveur : XXX.XXX.130.2
    • Client : XXX.XXX.130.1


    (je passe la création des sockets, en mode connecté)

    1. Serveur -> CAsyncSocket::Listen()
    2. Client -> Connect(...,XXX.XXX.130.2,5555)
    3. Serveur -> Accept
    4. Serveur -> CAsyncSocket::OnAccept{Accept(NewCAsyncSocket)}
    5. Serveur -> NewCAsyncSocket::Send(49166 Octets) : en deux Send() (7 octets de header et 49159 de données)
    6. Client -> OnDataAvailable{Récupération du Header de taille fixe, et lecture de n octets, n étant indiqué dans le header}
    7. For(i = 0; i < 10 ; i ++) Client -> Send(Confirmation,SizeOfConfirmation,MSG_OOB) => ça c'est pour forcer l'envoi (du moins je l'espérais : mais ça ne change au final rien)
    8. Serveur -> NewCAsyncSocket::OnReceive() : Read() x 2 : header de taille fixe et Données (taille indiquée dans le header).
    9. Déconnection du tout (déconnection "sauvage" via débuggeur, pas via close())


    Le bàt blesse au 8ème point : je ne reçois ma notification (message windows) que lors de la première réception. Après, c'est comme si plus rien n'était envoyé côté client. Bien que j'ai vérifié côté client que les données soient partis, ils semblent bloqués qqpart (l'analyse du renifleur devraient m'en dire plus, j'espère).

    Le résultat du renifleur au cours de cette expérience (Installé sur le Serveur) est en pièces jointe


    Et petite question en réponse à une question :
    TCP contient des mécanismes de gestion de flux, pourquoi ne pas s'en servire ?
    Euh... lesquels? Et pardon d'avance de cet aveu de profonde méconnaissance.
    Fichiers attachés Fichiers attachés

  6. #6
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 492
    Par défaut
    Je pense qu'il y a quelques lagunes au niveau des connaissances réseaux.

    TCP est un protocole transport au niveau 4 du model OSI de l'ISO.
    Il a les caractéristiques d'être orienté connexion et envoie en flux de données.
    Il doit donc avoir un mécanisme de création et de destruction de connexion et il n'y a pas de notion de message, c'est un flux d'octets qui passe par une socket TCP d'en un sans un un autre flux dans l'autre sens.
    Le protocole TCP est responsable du bon acheminement de toutes les octets envoyés d'un coté de la connexion vers l'autre coté.
    Il est lourd (TCP), mais il gère lui même la perte de paquet IP par réémission, la suppression de la duplication des paquet IP, le ré-ordonnancement des données venant des paquet IP qui arrivent dans le désordres etc...
    Dans toutes les tâches qu'il à faire, TCP gère plusieurs fenêtres d'émission et de réception, ainsi que des temporisateur pour ne pas noyer le destinataire des données ou le réseau d'interconnexion avec des données (la bufferisation TCP est l'un des mécanismes utilisés pour faire optimiser le trafic réseau).
    En gros, il attend que le destinataire est acquitté une partie des données avant dans n'envoyer d'autre. La taille des données que peut envoyé l'émetteur sans acquittement du destinataire est appelé : la taille de la fenêtre d'émission.
    Une déconnexion "propre" oblige les deux extrémités à vérifier que toutes les données envoyées par l'un des intervenant ont été lu par l'autre.

    La gestion du flux est intrinsèque au protocole TCP. Cela n'empêche pas que si la couche cliente émettrice envoie trop de données, la socket enverra une erreur car elle n'aura plus assez d'espace pour enregistrer les données avant leur envoies et leur acquittement par le destinataire.

    TCP dispose d'une rustine vise à vis de son mode de fonctionnement en flux.
    Cette rustine est appelée : l'envoie de caractères urgents ou Out Of Band (OOB).
    Ce mécanisme permet d'avoir des envois de données qui peuvent dépasser les données déjà émissent de manière normale. Les données normales forme le flux (la Bande), les données envoyées en Urgence sont hors de la bande (Out Of Bande).
    Cela permet de les lire sans avoir à lire tous les octets envoyés avant.
    Etant donné qu'elles doublent tout le monde, il faut utilise une primitive de lecture spéciales pour les lires. Il est même possible de déterminer la position que ces données auraient dû avoir si elles avaient été envoyées normalement (C'est un espèce de marqueur DANS la bande).

    Le OOB de votre primitive ne fait qu'envoyer des données hors du flux de la connexion. Pour preuve le flag "URG" sur les paquets IP à partir du 74 dans les traces du sniffeur.

    Vous n'êtes pas notifié de la présence dans le flux car il n'y a de données dans le flux mais hors du flux.
    Si je me rappel bien, la lecture du marqueur dans le flux permet de lire les données hors bande comme si elles venaient dans la bande.

    Donc, si vous utilisez TCP, autant utiliser toutes les fonctionnalités qu'il offre (gestion des flux).

    Dans les traces, le client n'envoie jamais de données dans la bande, donc le comportement du serveur me paraît logique.

    Il faut donc enlever le OOB. Voir si cela marche correctement. Sinon, réutilisez le sniffeur pour vérifier qu’il n’y pas de bufferisation sur le client. S’il y a bufferisation, changez ke paramétrage de la socket client pour le désactiver.

    P.S.: le sniffer dispose de toute une panoplie de filtre, cela permet d'avoir que les paquets pertinents pour l'analyse (votre DHCP est un très grand bavard)

  7. #7
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Octobre 2008
    Messages : 179
    Par défaut
    Je pense qu'il y a quelques lagunes au niveau des connaissances réseaux.
    c'est un euphémisme à mon sujet, si je peux me permettre!
    P.S.: le sniffer dispose de toute une panoplie de filtre, cela permet d'avoir que les paquets pertinents pour l'analyse (votre DHCP est un très grand bavard)
    J'ai configuré le sniffer pour me limiter aux paquets TCP. J'avais par contre oublié de perpétuer ce filtre (visuel) au moment de la sauvegarde : mea culpa.



    l'OOB était un surtout une tentative désespérée. Je connaissais vaguement le principe sans le maîtriser toutefois. Merci de votre explication en tous cas.
    Petit point à ce sujet : les données OOB sont notifiées par la classe CAsyncSocket comme un message normal (::OnReceive), mais après être passées par le callback ::OnOutOfBandData. J'ai constaté que je perdais systématiquement le dernier octet dans l'affaire.... donc en conclusion, le temps de mieux maîtriser le truc, je range ça au placard.

    Après correction, je lance 2 tests :
    D'abord, le même que précédemment, et cette fois, mes 50 messages sont reçus normalement.

    Ensuite, ce second test :
    1. Serveur -> CAsyncSocket::Listen()
    2. Client -> Connect(...,XXX.XXX.130.2,5555)
    3. Serveur -> Accept
    4. Serveur -> CAsyncSocket::OnAccept{Accept(NewCAsyncSocket)}
    5. Serveur -> NewCAsyncSocket::Send(49166 Octets) : en deux Send() (7 octets de header et 49159 de données)
    6. Client -> OnDataAvailable{Récupération du Header de taille fixe, et lecture de n octets, n étant indiqué dans le header}
    7. Client -> Send(Confirmation,SizeOfConfirmation,0)
    8. Serveur -> NewCAsyncSocket::OnReceive() : Read() x 2 : header de taille fixe et Données (taille indiquée dans le header).
    9. Répéter les étapes 5-6-7-8


    Normalement, ça devrait boucler, mais cette fois, au bout de qqs confirmations reçues, une confirmation n'arrive jamais (ou pour être plus précis CAsyncSocket::OnReceive() n'est jamais invoqué), ce qui bloque mon processus. Ce qui me surprend puisque le sniffer a l'air de confirmer la réception du message de confirmation côté serveur (paquet 226 en acquittement du 225 si j'ai tout compris et que j'ai bien lu les numéros de séquence).

    Voici un petit log (un timer déclenché au moment de l'envoi vérifie qu'on n'attend pas indéfiniement une confirmation) :
    MSG 18:07:41:906 | Client Connected : XXX.XXX.130.1 on Port : 49184
    MSG 18:07:42:046 | Confirmation reçue : 49166 octets traités.
    MSG 18:07:42:046 | Envoyés 49166 Octets
    MSG 18:07:42:328 | Confirmation reçue : 49166 octets traités.
    MSG 18:07:42:343 | Envoyés 49166 Octets
    MSG 18:07:42:687 | Confirmation reçue : 49166 octets traités.
    MSG 18:07:42:687 | Envoyés 49166 Octets
    MSG 18:07:43:125 | Confirmation reçue : 49166 octets traités.
    MSG 18:07:43:125 | Envoyés 49166 Octets
    MSG 18:07:44:250 | Plus aucune confirmation depuis 5 secondes


    J'ai rajouté, pour ce cas là, un petit test du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    		if (ConfirmationPerdue)
    		{
    			char buff[25];
    			m_Server->m_DiplomatServer->Receive(buff,25,0);
    		}
    Et là, "miracle", mes données sont là.... ce n'est évidemment pas la solution, mais ça me rassure bien sur le fait que les données sont disponibles. Est-ce que ça confirmerait la "bufferisation" côté Mac? Quid alors de ce qui ressemblait à une paire Push/acquittement (paquets 225/226)?
    Fichiers attachés Fichiers attachés

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 492
    Par défaut
    Si le paquet 225 suit bien immédiatement la notification fait pas le client, c'est qu'il n'y a pas de bufferrisation coté client (comme l'indique le flag PUSH,
    voisi une explication très clair du système, il faut lire les 2 pages)
    http://www.tcpipguide.com/free/t_TCP...shFunction.htm
    http://www.tcpipguide.com/free/t_TCP...Function-2.htm
    Si le paquet 226 suit immédiatement le paquet 225, c'est que la stack TCP/IP du serveur a fait correctement sont travail.

    Si toutes les conditions précédentes sont bien vérifiées, le problème est bien dans le code du serveur.
    Si vous regarder les remarques du MVP Joseph M. Newcomer sur ce thread
    http://www.tech-archive.net/Archive/...1/msg00699.htm
    Vous ne devriez pas utiliser ces classes. Le support réseaux dans les MFC ou WinInet a toujours été foireux.

  9. #9
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Octobre 2008
    Messages : 179
    Par défaut
    Error 404: The Resource You Requested Was Not Found
    Il y a un petit problème avec le lien que vous m'avez donné.

    Ce qui n'est plus très grave car, je viens tout juste de trouver, après une nuit passée à rêver de Sockets (pas idéal pour la récupération, je le confirme).

    En me basant sur vos remarques, et les résultats du sniffer, notamment ce qui s'est confirmé être un PSH/ACK correct des paquets 225/226, j'ai naturellement supposé que c'était bien la notification qui était perdue.
    Je me suis donc penché sur le message FD_READ correspondant à la notification d'octets disponibles dans le pipe... et c'est Google qui m'a finalement donné la solution : je fais plusieurs receive() dans ma fonction OnReceive() (un pour le header, et un pour les données décrites dans le header).
    Hors, si le message FD_READ est désactivé au moment de l'entrée dans OnReceive(), il est automatiquement réactivé lorsque j'appelle Receive(...). un FD_READ est donc envoyé à chaque fois que je lisais mon header, ce qui finissait par provoquer ce problème.

    En réponse à celà, mon traitement dans OnReceive est encapsulé dans une zone sans notification, pour éviter ça. Et ca fonctionne d'un seul coup à merveille!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CAsyncSocket::AsyncSelect(0);
    ...
    CAsyncSocket::AsyncSelect(FD_READ);

    Je vous dois en tous cas un grand merci, car j'ai appris énormément grâce à votre aide, et aurai sans doute planché beaucoup plus longtemps sans vos suggestions. Je promets à l'avenir d'utiliser plus souvent les Renifleurs réseaux


    PS :
    Vous ne devriez pas utiliser ces classes. Le support réseaux dans les MFC ou WinInet a toujours été foireux.
    Oui, de plus en plus souvent je regrette d'avoir choisi la facilité MFC plutôt qu'une librairie autre.... je commence doucement à migrer.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Plus d'affichage de réception sous windows terminal de windows 95
    Par Daetheia dans le forum Windows 2000/Me/98/95
    Réponses: 3
    Dernier message: 25/11/2011, 16h37
  2. Réponses: 10
    Dernier message: 05/05/2010, 09h16
  3. plus de notification en lecture seule
    Par bganata dans le forum Excel
    Réponses: 2
    Dernier message: 15/02/2010, 13h05
  4. CSocket qui saute au bout de quelques réceptions
    Par Deckard666 dans le forum MFC
    Réponses: 2
    Dernier message: 04/04/2007, 11h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo