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 :

[Systeme] Utiliser system() sans dupliquer la table des descripteurs de fichier


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut [Systeme] Utiliser system() sans dupliquer la table des descripteurs de fichier
    Salut,



    J'ai un petit problème dans une application serveur mono-thread "basique" qui boucle sur trois étapes :

    1. Attente d'une connexion avec accept().
    2. Traitement de la demande reçu (requête BD, exécution de programme externe, etc.).
    3. Envoi de la réponse au client.


    Tout fonctionne correctement sauf dans un cas précis où j'exécute une commande externe avec un simple system() qui lance un script en tâche de fond :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    system ("monscript &");
    Dans certain cas "monscript" peut être vraiment très long (plus de 5 minutes), et c'est pour cette raison je le lance en tâche de fond, surtout que je n'ai pas du tout besoin d'attendre qu'il soit fini pour renvoyer la réponse...

    De ce point de vue là cela fonctionne "correctement" : le serveur continue, écrit la réponse dans la socket, la ferme et se remet en attente sur le accept().


    Le problème étant que system() utilise un fork() qui duplique la table des descripteurs de fichier. Et donc mon script conserve la socket de réponse ouverte. Ainsi malgré que mon serveur ai bien envoyé la réponse, le client reste bloqué car il attend que la socket soit véritablement fermé... (et donc la fin du script).


    Je voudrais donc remplacer l'utilisation du system() par un fork() que je gèrerais mon même et où je fermerais les descripteurs de fichier, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    pid_t   pid;
     
    pid = fork ();
    if (pid == 0) {
    	/* Dans le processus fils */
     
     
    	/* COMMENT FAIRE : fermer tous les descripteurs de fichier autre que 0, 1 et 2 */
     
    	/* Puis on utilise system() tout simplement */
    	system("monscript &");
    	exit(0);
    }
    Le problème étant que je ne n'ai pas accès à la socket ouverte à ce niveau là, mais surtout que je voudrais pour réutiliser le code et faire quelque chose de générique.

    Ma question est donc : comment fermer tous les descripteurs de fichier autre que stdin, stdout et stderr ?




    a++

  2. #2
    Membre chevronné Avatar de cmoibal
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    361
    Détails du profil
    Informations personnelles :
    Localisation : Tunisie

    Informations forums :
    Inscription : Avril 2007
    Messages : 361
    Par défaut
    salut,


    je pense pas que c'est possible de fermer la socket avant que ton serveur envoie la réponse au client, non ?

    je pense qu'une simple solution se présente : c'est d'envoyer la réponse fermer la socket et puis lancer le script.

  3. #3
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par cmoibal Voir le message
    je pense pas que c'est possible de fermer la socket avant que ton serveur envoie la réponse au client, non ?
    Il faut fermer la socket seulement dans le processus fils.
    J'ai testé et cela marche très bien mais je ne souhaite pas me trimballer la socket partout dans le code (pour le moment j'ai fait "crade" en passant la socket en global mais je souhaiterais faire quelque chose de propre si possible)

    Citation Envoyé par cmoibal Voir le message
    je pense qu'une simple solution se présente : c'est d'envoyer la réponse fermer la socket et puis lancer le script.
    Le problème c'est que cela imposerait quand même pas mal de changement dans le fonctionnement du serveur... ce que je ne souhaiterais pas...

    a++

  4. #4
    Membre chevronné Avatar de cmoibal
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    361
    Détails du profil
    Informations personnelles :
    Localisation : Tunisie

    Informations forums :
    Inscription : Avril 2007
    Messages : 361
    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
     
    pid_t   pid;
     
    pid = fork ();
    if (pid == 0) {
    	/* Dans le processus fils */
     
     
    	/* COMMENT FAIRE : fermer tous les descripteurs de fichier autre que 0, 1 et 2 */
     
    	/* Puis on utilise system() tout simplement */
    	system("monscript &");
    	exit(0);
    }
    d'aprés le code, vous ne fermer pas la connexion dans le processus fils, donc, tu va la fermer aprés, non ?
    Dans certain cas "monscript" peut être vraiment très long (plus de 5 minutes), et c'est pour cette raison je le lance en tâche de fond, surtout que je n'ai pas du tout besoin d'attendre qu'il soit fini pour renvoyer la réponse...
    Donc, t'as pas besoin de connaitre l'état de ton script.

    1. Attente d'une connexion avec accept().
    2. Traitement de la demande reçu (requête BD, exécution de programme externe, etc.).
    3. Envoi de la réponse au client.
    il suffit donc de faire le 3. avant d'exécuter le programme

    et s'il y a beaucoup de changement a faire, je pense que c'est nécessaire... car le serveur n'est pas bien conçut ....

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par cmoibal Voir le message
    d'aprés le code, vous ne fermer pas la connexion dans le processus fils, donc, tu va la fermer aprés, non ?
    Je la ferme au niveau du commentaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /* COMMENT FAIRE : fermer tous les descripteurs de fichier autre que 0, 1 et 2 */
    Avec un code du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    close(monSockDefiniEnGlobal);
    Mais :
    • Je ne voudrais pas avoir à utiliser une variable globale pour cela.
    • Je voudrais si possible un code générique qui me ferme tous les fichiers/sockets ouverts.


    Citation Envoyé par cmoibal Voir le message
    et s'il y a beaucoup de changement a faire, je pense que c'est nécessaire... car le serveur n'est pas bien conçut ....
    C'est surtout que j'utilise une librairie interne qui gère tout cela et ce fonctionnement est utilisé pour plusieurs serveurs... Je préfère éviter de changer ce qui fonctionne... De plus c'est seulement le script qui est inutile dans la réponse, mais certaines données utilisé pour lancer le script sont aussi utile pour la réponse...

    Sincèrement je ne souhaite pas modifier l'ordonnancement de ces trois étapes.


    Pour le moment je vais rester comme cela et simplement fermer ma socket...


    Mais je garde le sujet ouvert si jamais quelqu'un sait comment fermer tous les flux ouvert sans forcément avoir leurs descripteurs...

    a++

  6. #6
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Je remonte ce "vieux" post pour donner la solution adopté.


    Je n'ai pas vraiment trouver la solution permettant de fermer tous les descripteurs de fichier, mais par contre j'ai trouvé une solution permettant de marquer les descripteurs afin qu'ils soient fermés lorsqu'une fonction exec() est appelée...

    Pour cela j'ai utilisé cette fonction :
    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
    	/* Set the FD_CLOEXEC  flag of desc if value is nonzero,
    	   or clear the flag if value is 0.
    	   Return 0 on success, or -1 on error with errno  set. */ 
     
    	int set_cloexec_flag (int desc, int value)
    	{
    	  int oldflags = fcntl (desc, F_GETFD, 0);
    	  /* If reading the flags failed, return error indication now. */
    	  if (oldflags < 0)
    	    return oldflags;
    	  /* Set just the flag we want to set. */
    	  if (value != 0)
    	    oldflags |= FD_CLOEXEC;
    	  else
    	    oldflags &= ~FD_CLOEXEC;
    	  /* Store modified flag word in the descriptor. */
    	  return fcntl (desc, F_SETFD, oldflags);
    	}
    Cette fonction permet de mettre/retirer un "flag" FD_CLOEXEC sur un descripteur (fichier ou socket). Ce flag permet de fermer le descripteur dès qu'une des méthodes exec() est appelée

    Du coup il suffit d'appeler la fonction lors de la création de la socket afin qu'elle ne soit plus "partagée" avec les programmes fils :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    socket = accept(...);
    set_cloexec_flag (socket, 1);
    Plus de détail (en anglais) : http://www.cs.ui.ac.id/WebKuliah/IKI...tor_Flags.html


    a++

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 13/05/2014, 08h55
  2. system d'exploitation et table des pages
    Par sarainformatique dans le forum Administration système
    Réponses: 0
    Dernier message: 12/12/2008, 18h10
  3. Réponses: 1
    Dernier message: 22/01/2007, 16h10
  4. Test du systeme - utilisation de -D de gcc
    Par Toutankharton dans le forum Autres éditeurs
    Réponses: 2
    Dernier message: 14/12/2006, 23h33
  5. Réponses: 5
    Dernier message: 27/01/2006, 18h48

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