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

Réseau C Discussion :

Socket / Select / temps de reponse


Sujet :

Réseau C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut Socket / Select / temps de reponse
    Salut a tous,

    J'utilise sur mon programme (un mini-irc tel que celui qui se trouve sur le tutoriel sur ce site) la commande select sans monitorer les actions en ecritures ni le timeout.
    j'aimerai tout de meme y ajouter une petite feature.

    J'aimerai que le client puisse effectuer une action sur le server qui demande par contre un certains temps. En fait j'aimerai que le server, apres avoir recu la requete du client, mette par exemple 5 secondes avant de lui repondre.

    J'avais pense a sleep mais cela ne peut marcher car cela bloquerait tout le server, ainsi si plusieurs clients font cette requete a 1 seconde d'intervalle, tout planterait totalement.

    Donc ma question est comment je dois proceder pour gerer ce temps de reponse du serveur en fonction du moment ou il recoit la requete du client ? Je sais qu'il s'agit d'utiliser le timeout de select, enfin je suppose mais je ne vois pas comment faire.

    si quelqu'un pouvait me donner quelques indications a suivre, je lui en serais tres reconnaissant.

    Merci

  2. #2
    Invité
    Invité(e)
    Par défaut
    Le timeout de select n'est pas la bonne solution, car si l'appel à select se termine avant le delai que tu lui as indiqué, tu n'as aucun moyen de savoir combien de temps il reste, car POSIX précise seulement que la structure timeval peut être changée, mais sans préciser de quelle façon.
    Si tu es sous Linux, il se peut que la structure soit mise à jour, mais il se peut que cela dépende des distributions, car les man ne disent pas la même chose partout.

    Bref, il te faut chercher ailleurs, par exemple du côté de la fonction alarm sous Linux.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 450
    Par défaut
    +1 pour les remarques de feydaykyn.

    Cela dit, les autres appels bloquants d'UNIX sont soumis aux mêmes contraintes. Un sleep(), par exemple, peut se réveiller avant terme si un signal est reçu entre temps.

    Il faut considérer d'autre part que beaucoup de choses peuvent réveiller ton processus avant terme, mais que celui-ci peut également être retardé (dans des proportions bien moindres cela dit) par les overheads dus au multitâche ou au système lui-même s'il est surchargé.

    Dans tous les cas, pour faire ce genre de choses, je m'établis un « calendrier », c'est-à-dire que je m'enquiers de l'heure courante (timestamp), que j'ajoute la durée nécessaire pour obtenir l'heure exacte à laquelle doit se produire l'événement, et je place cette valeur dans un buffer circulaire ou une liste chaînée. Les éléments de cette liste sont triés dans l'ordre chronologique, du prochain au plus lointain.

    Ensuite, je me mets en sommeil soit avec alarm(), soit avec le timeout de select(), soit directement avec sleep() si je n'ai rien d'autre à faire, pour une durée qui me permet d'atteindre le premier événement.

    Lorsque que je me fais réveiller, je m'enquéris à nouveau de l'heure courante et je solde tous les événements dont le timestamp est inférieur à la date courante. Leur nombre peut être nul si je me suis fait réveiller trop tôt, ou multiple si j'ai du retard, mais peu importe : la façon de traiter la chose est identique. Ensuite, j'examine l'échéance du prochain événement, je calcule le laps de temps qui m'en sépare, je boucle et me remets en sommeil comme indiqué au précédent paragraphe.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut
    Merci de vos reponses.
    Je vais regarder ca attentivement.

    Je vous fais signe bientot

  5. #5
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    J'ai deja eu un projet de ce type a faire, sous unix aucun probleme avec le timeout du select qui te donne le temps restant, mais sous windows, effectivement on est pas assurer de ce qu'il reste.

    J'ai donc utiliser les timestamp, tu recupere le nombre de seconde ecouler entre l'appel du select et la sortie du select, tu mets a jour la liste de tes client et quand un compteur (stocker dans une structure de tes clients) passe a 0, tu envoi le message si tu veux je peux essayer de te retrouver un bout de code avec tout sa

    Edit: j'avais mal lu le commentaire d'obsidian, et donc repondu la meme chose que lui mais differemment, desoler du double mais ma proposition de code tiens toujours

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut
    Merci pour ta reponse
    oui je veux bien un extrait de code qui implemente cela.

    ps : je fais cette apply uniquement sous unix

  7. #7
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    /*
    ** my_loop.c for zappy in /home/skeud/programme/epitech/zappy/serveur/src
    ** 
    ** Made by escudi_r
    ** Login   <escudi_r@epitech.net>
    ** 
    ** Started on  Fri Apr 30 16:24:02 2010 escudi_r
    ** Last update Sat Jun 19 14:20:53 2010 escudi_r
    */
     
    #include "serveur.h"
     
    int	my_loop_end(s_zappy *zappy)
    {
      //met a jour tout les clients (zappy contient une liste chainee de client)
      update_time(zappy);
      //parcour tout les client pour savoir si il faut leur envoyer une reponse
      write_all(zappy);
      return (ERROR);
    }
     
    int	init_my_loop(struct s_zappy *zappy, struct timeval *heure)
    {
      int	max;
     
      //permet de trouver le temps minimum et de le setter pour le select
      put_time(zappy);
      FD_ZERO(&zappy->readf);
      FD_ZERO(&zappy->writef);
      max = set_fd(zappy);
      //initialise l'heure pour pouvoir la compter plus tard
      gettimeofday(heure, NULL);
      return (max);
    }
     
    int	change_time(struct timeval *timer, struct timeval *heure)
    {
      gettimeofday(&heure[1], NULL);
      heure[1].tv_sec -= heure[0].tv_sec;
      heure[1].tv_usec -= heure[0].tv_usec;
      if (heure[1].tv_usec < 0)
        {
          heure[1].tv_sec--;
          heure[1].tv_usec += SECONDE;
        }
      timer->tv_sec -= heure[1].tv_sec;
      timer->tv_usec -= heure[1].tv_usec;
      if (timer->tv_usec < 0)
        {
          timer->tv_usec+=SECONDE;
          timer->tv_sec--;
        }
      if (timer->tv_sec < 0)
        {
          timer->tv_sec = 0;
          timer->tv_usec = 0;
        }
    }
     
    int			my_loop(struct s_zappy *zappy)
    {
      int			continuer;
      int			max;
      struct timeval	heure[2];
     
      continuer = 1;
      // boucle principale
      while (continuer)
        {
    	  //initialisation de la boucle
          max = init_my_loop(zappy, &heure[0]);
    	  //select
          if ((max = 
    	   select(max + 1, &zappy->readf, &zappy->writef,
    		  NULL, zappy->real)) == -1 && errno != EINTR)
    	{
    	  //erreur du select
    	  perror(P_SELECT);
    	  return (ERROR);
    	}
          if (zappy->real)
    	   //met a jour le conteur pour connaitre le temps passer dans le select
    	   change_time(zappy->real, heure);
    	  //appel la fonction de fin de boucle
          continuer = my_loop_end(zappy) == FIN || continuer == 0 ? 0 : 1;
        }
      return (SUCCESS);
    }
    Voila je pense avoir mis les bons commentaire au bon endroit.

    Pour info, ma structure de client contient un timestamp qui me donne le nombre de seconde avant l'envoi de donnee.

    Si tu as des questions sur mon code hesite pas

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     
    FD_ZERO(&zappy->readf);
    FD_ZERO(&zappy->writef);
    max = set_fd(zappy);
    Pourquoi tu utilises un writef ?
    tu controles les ecritures sur les socket par le server mais je ne vois pas l'interet.
    Pour le read je suis ok car tu fais un isset sur tes sockets clients pour savoir si elles ont changees d'etats et si le server doit recupere des requetes du client

  9. #9
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    ahah cher ami tu pourras apprendre par tes depend qu'un write peut echouer , et oui, ou une socket peu etre bloquante a l'ecriture, sa arrive dans 0,01% des cas mais c'est fesable.

    c'est pour sa que je test pour savoir si je peux ecrire, si je peux j'envois sinon j'envois pas et mon serveur ne reste pas bloquer sur l'ecriture de cet socket

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut
    Oui d'accord, mais lors d'un isset sur les sockets clients,
    si une d'entre elles a changee d'etat(autrement dit, il y a des donnees a lire dessus),
    si je catch avec le select ce changement, j'envoie dans une autre fonction prenant en argument la socket du client en question, ainsi je reponds avec le server en faisait un send en fonction de la demande du client pour lui repondre.

    ainsi si le send foire, ba je bloque avec un exit, donc pourquoi aurais je besoin d'un champ writefs ?

  11. #11
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    Imagine que tu as un serveur de jeu, que pres de 100 personnes sont connecter dessus en train de jouer, que seul un client foire, tu exit ton serveur et deconnecte 99 joueurs, avoue qu'ils risquent de tirer une sale tete

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut
    j'avoue pas faux

    mais d'un autre cote, dans ce cas jpeux afficher une erreur et close la socket du client en question et le delete de mon tableau de clients ?
    ainsi plus besoin du writefs.

    nan ?

  13. #13
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par skeud Voir le message
    J'ai deja eu un projet de ce type a faire, sous unix aucun probleme avec le timeout du select qui te donne le temps restant, mais sous windows, effectivement on est pas assurer de ce qu'il reste.
    Attention, la structure timeval n'est PAS mise à jour sous tous les linux, je ne connais qu'Ubuntu qui le fasse, mais ni Debian ni ArchLinux ne le font. Tu ne peux donc pas te servir de timeval pour l'utilisation que tu as en tête, à moins d'être certain que le système sur lequel sera éxécuté le programme ne change jamais.

    Pour vérifier comment agit ton système avec timeval, lit la page de man de la fonction select et s'il n'est pas écrit spécifiquement que la structure est mise à jour, ne compte pas dessus.

  14. #14
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    yep yep je sais, le serveur devait fonctionner sur fedora et windows 7, donc pour les deux j'ai verifier, puis de toute facon, on voit tres vite si sa fonctionne ou pas en testant le serveur.XD

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 37
    Par défaut
    dans ta boucle infinie,
    a quel moment tu regardes les changements sur les sockets en lecture ?
    car je vois que tu verifies en premier si il y a des donnees a ecrire aux clients mais a quelle moment tu verifies si tu dois lire des donnees requetes des clients ?

  16. #16
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    Dans my_loop_end() j'avais une grosse boucle que j'ai retirer, comme la question n'etait pas de lire ou d'ecrire sur les socket mais le timeval je boucle sur ma liste chainer de client et fesant des FD_ISSET sur chacun des client

Discussions similaires

  1. Temps de reponse sur Select avec Jointure
    Par Guigsounet dans le forum SQL
    Réponses: 15
    Dernier message: 30/07/2010, 10h29
  2. Pb de socket : select() et send()
    Par olive_le_malin dans le forum Réseau
    Réponses: 16
    Dernier message: 11/06/2006, 11h42
  3. Réponses: 4
    Dernier message: 13/03/2006, 17h46
  4. socket & select
    Par keyra dans le forum Réseau
    Réponses: 7
    Dernier message: 29/01/2006, 16h17
  5. ameliorer le temps de reponse
    Par subzero82 dans le forum MS SQL Server
    Réponses: 7
    Dernier message: 22/08/2005, 12h18

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