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 Discussion :

Lancer et arrêter un programme externe


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de dark_vidor
    Homme Profil pro
    Élève
    Inscrit en
    Janvier 2005
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Élève

    Informations forums :
    Inscription : Janvier 2005
    Messages : 321
    Par défaut Lancer et arrêter un programme externe
    Bonjour,

    Dans le cadre de mes études j'essaye de monter un serveur TCP en C, un client TCP/serveur WebSocket en Node.JS et un client final en HTML.

    Nom : Dessin1.png
Affichages : 464
Taille : 34,5 Ko

    J'ai déjà une partie qui tourne sur un Raspberry.
    Le Server en C est se contente de renvoyer l'heure quand il reçoit un message. Il est lancer dans un thread et pour l'instant le serveur est bloquant, je dois regarder du coté de select() pour le rendre non bloquant.

    Dans un premier temps j'aimerai implémenter le lancement et l'arrêt automatique du client/serveur en Node.JS directement avec mon code en C.
    J'ai trouvé la commande system() mais je ne comprends pas comment récupérer le PID de la commande exécutée.
    De même en cas d'interception de signal il faudrait tuer le client/serveur en Node.JS.

    Le code est ici : https://github.com/a-tortevois/tcp-s...-client-server

    Merci pour votre aide.

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par dark_vidor Voir le message
    Dans un premier temps j'aimerai implémenter le lancement et l'arrêt automatique du client/serveur en Node.JS directement avec mon code en C.
    J'ai trouvé la commande system() mais je ne comprends pas comment récupérer le PID de la commande exécutée.
    Mauvaise idée. La commande system() est une commande en mode "tire et oublie". Elle te permet effectivement de lancer un programme externe mais le lance sans te donner aucune possibilité de contrôle. Et en plus elle est bloquante, c'est à dire qu'elle attend la fin de la commande exécutée pour te rendre la main et tout ce que tu peux espérer récupérer c'est l'état du programme exécuté quand il se termine.

    Il te faut t'orienter vers le couple fork() + exec(). C'est le stantard dans ce type de programmation. Le process se duplique avec fork(). La partie père récupère le pid du fils (ce que tu veux) et la partie fils lance le programme choisi au travers d'une des primitives exec(). En effet il y en a 6 différentes selon ton besoin: les 3 premières de la famille "l" qui reçoivent les paramètres sous forme de liste et où on trouve execl() (la base), execlp() (utilise le PATH pour chercher la commande à exécuter), execle() (tu peux lui passer un environnement) ; et les 3 autres de la famille "v" qui reçoivent les paramètres sous forme de tableau et où on trouve 3 fonctions similaires execv(), execvp() et execve(). Et là, à la différence de system(), le père a le choix d'attendre la fin du fils (donc d'attendre la fin de la commande) via un wait() ou pas.

    Tu pourrais être tenté par le couple fork() + system() dans le fils mais là aussi ce serait une mauvaise idée car à la différence de exec() qui remplace le process courant par celui du programme à exécuter, system() génère son propre fils pour exécuter le programme. Tu aurais donc ton propre fils (que tu maitrises) ayant généré son propre fils (que tu ne maitrises pas) et sur lequel tu n'aurais aucune action (et donc surtout pas possibilité d'arrêter le programme exécuté).

    Accessoirement ta solution de thread qui renvoie l'heure aurait peut-être avantage à basculer elle-aussi plutôt sur un fork() avec le fils généré qui se contente là de renvoyer lui-même l'heure demandée (donc là pas besoin de exec()).

    Citation Envoyé par dark_vidor Voir le message
    De même en cas d'interception de signal il faudrait tuer le client/serveur en Node.JS.
    Pas de souci: avec le couple fork() + exec() le père connait le pid de ton node/js, il peut lui envoyer un kill() à la demande.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre éclairé Avatar de dark_vidor
    Homme Profil pro
    Élève
    Inscrit en
    Janvier 2005
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Élève

    Informations forums :
    Inscription : Janvier 2005
    Messages : 321
    Par défaut
    Merci pour cette réponse détaillée et constructive.
    Je vais étudier le fork() et le exec() de près dès demain.

    Citation Envoyé par Sve@r Voir le message
    Bonjour
    Accessoirement ta solution de thread qui renvoie l'heure aurait peut-être avantage à basculer elle-aussi plutôt sur un fork() avec le fils généré qui se contente là de renvoyer lui-même l'heure demandée (donc là pas besoin de exec()).
    In fine non je ne pense pas, car ça ne sera pas l'heure qui va être renvoyé mais des variables du programme principal (qui se résume dans l'exemple en un usleep(), mais en vrai j'ai du code ), l'idée est de faire un push des variables quand il y a une modification (d’où implémentation d'un serveur non bloquant), de les envoyer via la socket en TCP et des récupérer sur des web socket pour afficher sur une IHM (un site web local) et envoyer pouvoir envoyer sur un cloud ou un API.

    Je suis partie comme cela pour ne pas à avoir à gérer plusieurs clients dans le code en C et ne pas avoir à gérer du web socket, pour que le "serveur" en C reste simple et relativement souple à maintenir.
    L'idée c'est de déléguer la gestions des "clients externes" à mon "client TCP-serveur-Node.JS" (puisque mon IHM sera basé sur React ou Angular, donc j'aurai déjà du Node.JS) qui sert de "passerelle" avec le code en C et les différents services qui pourraient venir s'interfacer avec.
    C'est n'est pas cette brique qui est la plus complexe à construire et ça fera très bien le "job" sans surcharger le RPi.
    (Et puisque parce que je suis faignant et que j'avais pas envie de refaire un truc en C alors que en Node.JS c'est déjà très bien fait ^^, mais ça faut pas le dire )

    J'ai rajouté le code d'un serveur non bloquant, il me reste quelques bugs à corriger...
    Quand je rentre dans le "timeout", les messages ne sont plus détecté

    Restant à l'écoute des suggestions et remarques.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dark_vidor Voir le message
    Je vais étudier le fork() et le exec() de près dès demain.
    Petit exemple de démo
    Code c : 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
    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/wait.h>
     
    void fils() {
    	printf("Je suis le fils (%d) - Mon père est %d\n", getpid(), getppid());
    	sleep(10);				// Attente (pour démo)
    	execl("/bin/ls", "/bin/ls", "-l", "-a", NULL);
    	printf("test\n");			// Ne sera jamais exécuté, le execl() a remplacé ce code par celui du "ls"
    }
     
    int main(int argc, char *argv[]) {
    	pid_t pid;
    	switch(pid=fork()) {
    		case -1: // Erreur
    			fprintf(stderr, "Erreur fork() - %s\n", strerror(errno));
    			break;
    		case 0: //Fils
    			fils();
    			break;
    		default: // Père
    			printf("je suis le père (%d) - pid fils: %d\n" , getpid(), pid);
    			// Attente fin fils
    			waitpid(pid, NULL, 0);
    			printf("Fils terminé\n");
    	}
    }

    Citation Envoyé par dark_vidor Voir le message
    In fine non je ne pense pas, car ça ne sera pas l'heure qui va être renvoyé mais des variables du programme principal (qui se résume dans l'exemple en un usleep(), mais en vrai j'ai du code )
    Hum... le souci c'est que je ne sais pas du tout comment Linux gère le mélange fork+thread. Ce sont tous deux des outils dédiés à programmer en multitâche mais l'un est natif Unix et l'autre provient du monde zindow et je ne suis pas certain qu'on puisse les mélanger. Enfin tu vas jouer à l'explorateur dans ce domaine...

    Citation Envoyé par dark_vidor Voir le message
    (Et puisque parce que je suis faignant et que j'avais pas envie de refaire un truc en C alors que en Node.JS c'est déjà très bien fait ^^, mais ça faut pas le dire )
    Très bonne philosophie. Inutile de réinventer ce qu'on peut récupérer
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre éclairé Avatar de dark_vidor
    Homme Profil pro
    Élève
    Inscrit en
    Janvier 2005
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Élève

    Informations forums :
    Inscription : Janvier 2005
    Messages : 321
    Par défaut
    Merci pour l'exemple.

    J'ai pensé à une autre solution ce matin : Mon programme en C est lancé par un service au démarrage, rien ne m’empêche (en théorie) de lancer un second service qui attends que le port soit en écoute pour lancer le "client TCP-serveur-Node.JS", et de coup la gestion du contrôle et des redémarrage des services est déléguée à Linux

    Je vais creuser ça ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #!/bin/bash
    echo "Wait for port 1998 is open"
    while netstat -lnt | awk '$4 ~ /:1998$/ {exit 1}'; do sleep 10; done
    echo "Port 1998 is now open"
    node wss.js

  6. #6
    Membre éclairé Avatar de dark_vidor
    Homme Profil pro
    Élève
    Inscrit en
    Janvier 2005
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Élève

    Informations forums :
    Inscription : Janvier 2005
    Messages : 321
    Par défaut
    Il semblerait qu'il y ai un problème en passant par les services, c'est bizarre :

    root@raspberrypi:~# systemctl status myapp.service
    ● myapp.service - MyApp Service
    Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
    Active: failed (Result: timeout) since Sun 2020-02-23 16:16:08 UTC; 11s ago
    Process: 589 ExecStart=/usr/bin/myapp (code=exited, status=1/FAILURE)
    Process: 590 ExecStartPost=/usr/bin/wss (code=killed, signal=TERM)
    Main PID: 589 (code=exited, status=1/FAILURE)
    Tasks: 0 (limit: 2200)
    Memory: 2.3M
    CGroup: /system.slice/myapp.service

    févr. 23 16:16:08 raspberrypi myapp[589]: Message send to the client: It's 16:15:05
    févr. 23 16:16:08 raspberrypi myapp[589]: Message received from the client: test
    févr. 23 16:16:08 raspberrypi myapp[589]: Message send to the client: It's 16:15:17
    févr. 23 16:16:08 raspberrypi myapp[589]: Message send to the client: It's 16:15:47
    févr. 23 16:16:08 raspberrypi myapp[589]: Catch SIGTERM
    févr. 23 16:16:08 raspberrypi myapp[589]: server_stop()
    févr. 23 16:16:08 raspberrypi myapp[589]: Thread `server` stop
    févr. 23 16:16:08 raspberrypi systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
    févr. 23 16:16:08 raspberrypi systemd[1]: myapp.service: Failed with result 'timeout'.
    févr. 23 16:16:08 raspberrypi systemd[1]: Failed to start MyApp Service.
    ----- Edit

    Il manquait un & à la fin de la commande, du coup le script bash déclenchait le timeout

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

Discussions similaires

  1. [Python 3.X] Lancer et cacher des programmes externes
    Par Naiyro dans le forum Général Python
    Réponses: 2
    Dernier message: 24/07/2018, 12h42
  2. Arrêter un programme externe
    Par codefree dans le forum Tkinter
    Réponses: 6
    Dernier message: 06/07/2014, 20h40
  3. lancer et controler un programme extern
    Par mouhab dans le forum VBScript
    Réponses: 0
    Dernier message: 09/02/2010, 13h41
  4. lancer et controler un programme externe en java
    Par mouhab dans le forum Langage
    Réponses: 1
    Dernier message: 25/08/2009, 16h51
  5. lancer un programme externe et continuer
    Par seal3 dans le forum C++
    Réponses: 6
    Dernier message: 31/10/2005, 19h00

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