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

C++Builder Discussion :

Eviter qu'un SocketClient se reconnecte +ieurs fois ou/et déconnecter un SocketClient


Sujet :

C++Builder

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut Eviter qu'un SocketClient se reconnecte +ieurs fois ou/et déconnecter un SocketClient
    Bjr,

    La longueur d'une chaine d'un titre n'étant pas assez longue pour ma discussion, je présice que je cherche un raisonnement et bien-sur des exemples de codes pour:

    1/- Réaliser une déconnection d'un SocketClient d'un SocketServer au bout d'un certains temps d'inactivité (en minutes),

    2/- Eviter qu'un SocketServer reçoit plusieurs SocketClient pour un même client.

    Dans le cas "2", on imagine qu'un Client se connecte pour la première fois à mon Serveur. Il y a donc la creation d'un SocketClient sur mon Serveur. Ils s'échangent des data et pour une raison quelconque mon Client se déconnecte (baisse d'alimentation etc...). Mon serveur ne déconnecte pas (proprement ou non) ce SocketClient car le Client lui-même n'en a pas fait la demande puisque c'est un accident.
    Mon Client n'ayant pas terminé ce qu'il avait à faire se connecte à nouveau à mon Serveur. Du coup mon Serveur perçoit le même Client comme un nouveau Client en lui affectant un nouveau Socket, et SocketHandle différent. Comment faire pour que mon Serveur ferme correctement l'ancien SocketClient avant d'accepter la nouvelle connexion de ce même Client?
    Je travaille en mode non bloqué et il m'est impossible de travailler dans le mode bloqué.
    Ai-je besoin d'un thread?

    Merci

  2. #2
    Membre confirmé
    Inscrit en
    Juillet 2004
    Messages
    51
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 51
    Par défaut
    Bonjour,

    Je te propose quelques pistes... ça vaut ce que ça vaut

    1/ Avec des Timers peut-être ? Côté client, un timer se réinitialiserait à chaque fois qu'il envoie des données au serveur. Si rien n'est transmis au serveur dans le délai imparti, alors il envoie un message d'info au serveur disant qu'il se déconnecte pour cause d'inactivité

    J'ai pensé mettre le timer côté client plutôt que côté serveur pour économiser des ressources... s'il devait y avoir 5000 clients je ne sais pas quel serait l'impact sur les performances ?


    2/ Là faut voir comment tu gères les clients... J'imagine que tes clients sont regroupés dans des listes; est-ce que tu ne pourrais pas créer une liste pour les déconnexions sauvages ? Quand une connexion est coupée tu places ton client dans cette liste. Et quand un client cherche à se connecter tu vérifies d'abord s'il n'est pas dans cette liste ? Selon comment tu gères tes clients tu dois pouvoir les retrouver par un point commun ( login + mdp ? Id unique ?).

    Vala c'était ma modeste contribution ^^

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut
    Merci pour ta contribution

    1-/ Ta solution est intéressante mais j'en reviens de suite à un prob qui que se passe-t-il si le client se réinitialise et se reconnecte au serveur alors que son delai n'a pas expiré? En principe le serveur crée un nouveau SocketClient jusqu'aux informations de l'adresse IP identique qui risque de créer un conflit/bug au niveau du serveur. C'est pour ça que je me demande s'il ne faut pas aussi un Timer du coté Serveur.

    2-/
    J'imagine que tes clients sont regroupés dans des listes; est-ce que tu ne pourrais pas créer une liste pour les déconnexions sauvages ?
    Mais comment détecter une déconnection sauvage ou non, car dans ce que tu écris si mon Client se connecte correctement (@IP+Login+Pwd) rien ne l'empêche d'être victime d'un accident d'alimentation. Dans ce cas que fait le serveur tjs à la reconnection d'un Client ayant les même paramètres TCP.

  4. #4
    Membre confirmé
    Inscrit en
    Juillet 2004
    Messages
    51
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 51
    Par défaut
    Alors, alors

    Tatouillons un peu de code !
    Commençons par la classe client (côté serveur donc)... Je ne mets que le minimum pour plus de clarté :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class client
    {
     AnsiString pseudo;  // pseudo du client
     AnsiString Id;        // son Id unique (ip + login + mdp + nomdupc + serial du DD) par exemple ^^
     TCustomWinSocket *mysocket; // pointeur vers le socket attribué au client
     bool AQuitteProprement;  // false par défaut
    };

    Dans l'évènement de connexion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //------------------------------------------------------------------------
    // ***** OnClientConnect *****
    //------------------------------------------------------------------------
    void __fastcall TForm1::sockClientConnect(TObject *Sender, TCustomWinSocket *Socket)
    {
     client *c = new client;
     c->mysock = Socket;   // notre pointeur pointe sur le socket attribué
    // Après tu mets ton client dans une liste (TList, liste chainee etc)
    MaListeDeClients->Ajouter (c);
    }
    J'en arrive à ce qui te préoccupe ^^
    Dans l'aide de Borland sur l'évènement de déconnexion du client on trouve ça :
    The TServerClientWinSocket that describes the server endpoint of the client connection is freed after OnClientDisconnect
    Donc, on peut se servir du pointeur TCustomWinSocket renvoyé par l'évènement pour rechercher le client dont il s'agit.

    Par ailleurs, si un client quitte proprement en prévenant le serveur alors tu passe son bool AquitteProprement à True.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    //------------------------------------------------------------------------
    // ***** OnClientDisconnect *****
    //------------------------------------------------------------------------
    void __fastcall TForm1::sockClientDisconnect(TObject *Sender, TCustomWinSocket *Socket)
    {
     // Socket est le socket du client qui a quitté (sauvagement ou pas)
     // Sachant que le socket ne sera libéré qu'après la fin de l'évènement
     // le pointeur est toujours valide
     // On va alors chercher dans notre liste de clients, lequel a un pointeur identique.
    client *c = MaListDeClients->RenvoyerClientSelonSocket (Socket);
    c->mysocket = NULL;
     
    // Après tu fais ce que tu veux de ton client :D
    if (c->AQuitteProprement) {FaireCeci (c);}
    else {FaireCela (c);}
    }

    Voilà, j'espere que ça pourra t'aider

  5. #5
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    bonjour,
    une solution très simple largement utilisée dans les applications professionnelles est l'utilisation d'un "signe de vie".
    le principe utilisé est très simple,le seveur envoie a chaque client connecté
    un datagrame de test à intervalle régulier , (par exemple toutes les minutes), chaque client répond a ce datagramme.
    il ne reste plus alors au serveur a contrôler que chaque client connecté aie répondu au datagramme, dans le cas contraire le serveur déconnecte la connection inactive

    Cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut
    Merci pour vos aides.
    Néanmoins je reste perplexe sur par exemple la solution de DjmSoftware qui me semble pas complète car si je crée un speudo protocole de "signe de vie" entre mes clients et mon serveur toutes les minutes, que se passe-t-il si au bout de 30sec j'ai l'un de mes clients qui s'est déconnecté et se reconnecte automatiquement avant le signe de vie?
    De mes tests je vois bien que le serveur crée un nouveau SocketHandle, pourtant l'adresse IP est la même.
    Que se passe-t-il une fois que le serveur a détecté qu'il y a deux SocketHandle avec des SocketRemoteAddress identique?
    Je reformule ma question plus précisément:
    Existe-t-il un évènement relatif aux sockets du serveur qui peut se déclencher juste avant que le SocketServeur est l'attribution du SocketRemoteAddress afin de déconnecter un Socket ayant déjà reçu ce même SocketRemoteAddress, en vu d'éviter une erreur ou bug?

  7. #7
    Membre confirmé
    Inscrit en
    Juillet 2004
    Messages
    51
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 51
    Par défaut
    En fait je ne comprends pas bien ton problème...

    De mes tests je vois bien que le serveur crée un nouveau SocketHandle, pourtant l'adresse IP est la même.
    Que se passe-t-il une fois que le serveur a détecté qu'il y a deux SocketHandle avec des SocketRemoteAddress identique?
    A mon avis rien du tout... Et ce serait normal... Si ton serveur est sur internet et que plusieurs pc en réseau local (cybercafé, lan à la maison etc.) se connectent à lui, ils auront la même adresse ip ^^ Faut bien qu'ils puissent tous se connecter en même temps. Et par ailleurs, ça permet aussi de pouvoir faire tourner plusieurs clients sur un seul pc...

    De toute façon, lorsqu'une connexion est interrompue (sauvagement ou pas), le socket est libéré.


    Existe-t-il un évènement relatif aux sockets du serveur qui peut se déclencher juste avant que le SocketServeur est l'attribution du SocketRemoteAddress afin de déconnecter un Socket ayant déjà reçu ce même SocketRemoteAddress, en vu d'éviter une erreur ou bug?

    Voilà ce que dis l'aide :
    When a client socket opens a connection, the following events occur:

    1An OnLookup event occurs prior to an attempt to locate the server socket.

    2The Windows socket is set up, and initialized for event notification.

    3An OnConnecting event occurs after the server socket is located.

    4The connection request is accepted by the server and completed by the client socket.

    5An OnConnect event occurs after the connection is established.

    Tu devrais peut-être nous en dire plus sur ton projet, car là je vois pas vraiment ton problème... Notamment pour éviter quel bug ? Quand un client se reconnecte le serveur initialise un nouveau socket pour lui, l'ancien ayant été libéré d'office. Je vois pas à quel niveau ça pourrait te poser problème...

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut
    Merci bru-no!

    En fait je cherche juste à comprendre le fonctionnement d'un ServerSocket.
    Si vous dites qu'il peut y avoir +ieurs Socket pour une même adresse IP sans créer de bug ça me va.

    De toute façon, lorsqu'une connexion est interrompue (sauvagement ou pas), le socket est libéré.
    Mais dans ce cas, pourquoi mon évènement SocketDisconnect n'est pas appelé?

  9. #9
    Membre confirmé
    Inscrit en
    Juillet 2004
    Messages
    51
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 51
    Par défaut
    Normalement l'évènement OnDisconnect doit se déclencher

    Tu es sûr de l'avoir bien implémenté ?

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut
    Dans mon évènement OnDisconnect, j'affiche un message dans une TListView.
    Quand mon server arrête proprement une connexion, il se déclenche. Si la connexion s'arrête accidentellement cette évènement n'est pas réalisé puisque je n'ai aucun ajout de message dans ma TListView.

  11. #11
    Membre confirmé
    Inscrit en
    Juillet 2004
    Messages
    51
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 51
    Par défaut
    Bon ben... je crois que tu as raison Après moults tests, en cas de coupure inopinée de la connexion, le socket n'est pas libéré et forcément ça ne peut que poser problème par la suite !

    On peut le vérifier grâce à la propriété ActiveConnections de la classe TServerWinSocket...

    Tu pouvais pas le dire tout de suite, non ? Mauvaise foi inside

    Alors, j'ai un truc à te proposer : quand le client quitte sauvagement, l'évènement OnClientError est lancé. A travers lui on peut récupérer le socket du client en rade, et le fermer manuellement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    /-------------------------------------------------------------------------
    // ***** OnClientError *****
    //------------------------------------------------------------------------
    void __fastcall TForm1 :: sockError(TObject *Sender, TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    if (ErrorCode == 10053)  // 10053 est l'ErrorCode correspondant à la disparitions subite du client ^^
    	{
    	 Socket->Close(); // merci et au revoir
                // A noter qu'ici l'évènement OnClientDisconnect va se lancer 
    	}
     
    ErrorCode = 0; // pour éviter un joli message d'erreur
    }
    Voilà, ça a l'air de fonctionner Dis moi ce que cela donne chez toi...

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut
    Je regarde et je te tiens au courant merci qd même pour ta grande participation

  13. #13
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    Bonjour
    le composant TSocket Serveur fonctionne de la manière suivante
    il crée un socket d'écoute en mode listening avec le Port désigné
    il crée un socket par client avec un autre numéro de port
    chaque socket client est en mode Etablished

    le serveur socket tient une liste des clients connectés sous forme d'une tableau
    lors de la femeture d'un client quelle soit d'origine désirés ou accidentelle c'est

    l'OS qui signale la perte de connection , le composant TserverSocket signale cette déconnection par l'évènement OnDisconnect.

    la connection concernée est alors en mode CLOSE_WAIT ce qui signifie que l'OS la terminera après un TIMEOUT

    Lors de la reconnection du client (déconnecteur) , l'OS peut lui attribuer le même socket ou un autre

    en espérant t'avoir aidé

    Cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    135
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 135
    Par défaut
    merci DjmSoftware,

    Sauf que je n'ai jamais l'évènement OnDisconnect qui se fait lors d'une perte de connexion.
    J'utilise un point d'acces alors est-ce de là que le problème vient?

Discussions similaires

  1. Eviter qu'un visiteur s'inscrive plusieurs fois
    Par bernard26000 dans le forum Langage
    Réponses: 2
    Dernier message: 06/01/2015, 15h12
  2. [MySQL] comment eviter de faire 2 fois la meme requete
    Par lelapinrusse dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 04/05/2008, 00h14
  3. Réponses: 10
    Dernier message: 18/07/2007, 17h36
  4. Eviter de charger la meme liste 365 fois
    Par ReaseT dans le forum ASP
    Réponses: 2
    Dernier message: 02/10/2006, 14h04
  5. [API WIN] Eviter qu'un prog se lance 2 fois...
    Par asher256 dans le forum Windows
    Réponses: 2
    Dernier message: 07/10/2005, 15h58

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