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/Web Python Discussion :

Simulation Mini Chat


Sujet :

Réseau/Web Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de RowanMayfair
    Femme Profil pro
    Développeuse Freelance
    Inscrit en
    Mars 2019
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 48
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeuse Freelance

    Informations forums :
    Inscription : Mars 2019
    Messages : 247
    Par défaut Simulation Mini Chat
    Bonjour,

    Maintenant que je sais identifier des clients différents qui se connectent au serveur, je me suis dit qu'il fallait aller un peu plus loin, et je souhaite donc faire un mini-Chat. Un truc très simple (en théorie du moins ).
    Au départ, j'ai simplement modifié légèrement mon serveur pour qu'il prenne le nom de mon client, et transmette les messages reçu aux autres clients. Mais ça ne fonctionnait pas correctement, mon client recevait le message (de l'autre) uniquement quand il tapait quelque chose d'abord.
    Donc l'input bloquait la réception.
    Du coup, on m'a soufflé que le thread était une bonne idée.
    Mais.....ce que j'ai fait ne fonctionne pas comme je le souhaite.
    Les codes maintenant.
    Le serveur :
    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
    import socket
    import select
     
    hote = ''
    port = 12800
     
    connexion_principale = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connexion_principale.bind((hote, port))
    connexion_principale.listen(5)
    print("Le serveur écoute à présent sur le port {}".format(port))
     
    serveur_lance = True
    clients_connectes = []
    clients_sockets = {}
    n = ' '
    while serveur_lance:
        connexions_demandees, wlist, xlist = select.select([connexion_principale],
            [], [], 0.05)
     
        for connexion in connexions_demandees:
            connexion_avec_client, infos_connexion = connexion.accept()
            clients_connectes.append(connexion_avec_client)
     
        clients_a_lire = []
        try:
            clients_a_lire, wlist, xlist = select.select(clients_connectes,[], [], 0.05)
     
        except select.error:
            pass
        else:
            for client in clients_a_lire :
                if client not in clients_sockets :
                    client.send(b"Bienvenue sur le Tchat")
                    n = client.recv(1024)
                    n = n.decode()
                    clients_sockets.setdefault(connexion_avec_client,n)
     
                msg_recu = client.recv(1024)
                for client_tchat in clients_sockets :
                    msg_a_transmettre = clients_sockets[client_tchat].encode()\
                                        + b" : " + msg_recu
                    client_tchat.send(msg_a_transmettre)
                    print(msg_a_transmettre.decode())
     
                if msg_recu == "fin":
                    serveur_lance = False
     
    print("Fermeture des connexions")
    for client in clients_connectes:
        client.close()
     
    connexion_principale.close()
    Les threads :
    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
     
    from threading import Thread, RLock
     
     
     
     
    class Client_Rec(Thread):
     
        """Thread chargé simplement d'afficher les message envoyés par le serveur."""
     
        def __init__(self,connexion):
            Thread.__init__(self)
            self.connexion_avec_serveur = connexion
     
        def run(self):
            """Code à exécuter pendant l'exécution du thread."""
            msg_recu = ''
            while msg_recu :
                msg_recu = self.connexion_avec_serveur.recv(1024)
                print(msg_recu.decode())
     
     
     
    verrou = RLock()
     
    class Client_Envoi(Thread):
     
        """Thread chargé simplement d'envoyer des messages au serveur."""
     
        def __init__(self, connexion):
            Thread.__init__(self)
            self.connexion_avec_serveur = connexion
     
        def run(self):
            """Code à exécuter pendant l'exécution du thread."""
            msg_a_envoyer = b""
            while msg_a_envoyer != b"fin":
                with verrou:
                    msg_a_envoyer = input("> ")
                    msg_a_envoyer = msg_a_envoyer.encode()
                    self.connexion_avec_serveur.send(msg_a_envoyer)
    et les clients :
    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
    import socket
    from Tchat_client_thread import*
     
    hote = "localhost"
    port = 12800
     
    connexion_avec_serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connexion_avec_serveur.connect((hote, port))
    print("Connexion établie avec le serveur sur le port {}".format(port))
    print("Quel est votre nom ?")
     
    thread_Rec = Client_Rec(connexion_avec_serveur)
    thread_Envoi = Client_Envoi(connexion_avec_serveur)
     
    thread_Rec.start()
    thread_Envoi.start()
     
    thread_Rec.join()
    thread_Envoi.join()
     
     
    print("Fermeture de la connexion")
    connexion_avec_serveur.close()
    Désolée de mettre tout le code. Mais je ne sais pas identifier ce que j'ai mal fait.
    Est-ce mon verrou ? je l'ai mis sur l'input, parce que je voulais que la réception des messages soit prioritaire sur l'envoi. Ce n'était pas ce qu'il fallait faire ? Ou alors c'est autre chose ?

    D'avance, un grand merci à ceux qui auront la patience de se pencher sur mes petits problèmes

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 754
    Par défaut
    Salut,

    Citation Envoyé par RowanMayfair Voir le message
    Mais.....ce que j'ai fait ne fonctionne pas comme je le souhaite.
    Certes mais si vous ne précisez pas ce que vous souhaitez et en quoi le fonctionnement de votre code ne le fait pas....

    On est bien embêté car, çà, à priori, çà devrait marchoter...

    Sauf que comme on n'écrit pas une application réseau de façon aussi disons "dilettante", il y aurait plein de chose à revoir... et ce n'est peut être pas le sujet (en tous cas, la programmation réseau s'apprend et il y a tellement de bons tutos pour çà que...).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éclairé Avatar de RowanMayfair
    Femme Profil pro
    Développeuse Freelance
    Inscrit en
    Mars 2019
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 48
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeuse Freelance

    Informations forums :
    Inscription : Mars 2019
    Messages : 247
    Par défaut
    difficile de décrire ce qui se passe.
    Un test.
    Sur le serveur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Le serveur écoute à présent sur le port 12800
    Martine : Martine va à la plage
    Martine : pas de messages de l'autre client ?
    ClaudetteClaudette va à la plage : pas de messages de l'autre client ?
    Martine : et Claudette ,
    ClaudetteClaudette va à la plage : et Claudette ,
    Martine : ça se mélange
    ClaudetteClaudette va à la plage : ça se mélange
    Martine : client 2
    ClaudetteClaudette va à la plage : client 2
    Martine : client 1
    ClaudetteClaudette va à la plage : client 1
    Voilà tout est mélangé, le serveur affiche le message de l'un en l'affichant sur les 2...bref, tout mélangé
    Et sur les shell des clients, il n'y a que leurs propres messages qui s'affichent, le serveur ne transmet pas les messages des autres clients.

    L'objectif, c'est que les messages de Claudette s'affichent sur le shell de Martine au fur et à mesure, et réciproquement. Pour qu'elles puissent se répondre.

    Je n'ai pas la prétention d'apprendre la programmation réseau. Je souhaite rester au stade de l'initiation. Je ne comptais pas aller + loin que ce mini-Chat sur réseau local...mais j'aimerai bien réussir ça quand même.

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 754
    Par défaut
    Citation Envoyé par RowanMayfair Voir le message
    Voilà tout est mélangé, le serveur affiche le message de l'un en l'affichant sur les 2...bref, tout mélangé
    ah ben oui mais... il faut définir un protocole entre serveur et client.
    Par exemple, si vous écrivez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            for client in clients_a_lire :
                if client not in clients_sockets :
                    client.send(b"Bienvenue sur le Tchat")
                    n = client.recv(1024)
                    n = n.decode()
                    clients_sockets.setdefault(connexion_avec_client,n)
    vous supposez qu'après avoir ouvert la connexion, le client attend gentiment le message de bienvenue du serveur pour lui expédier la chaine de caractère qui permettra d'identifier le client.

    De plus, cette étape là suppose qu'il n'y a plus rien à lire pour ce client là...

    Après côté client, on doit avoir aussi un bout de code qui attend le message de bienvenue du serveur, expédie l'identifiant,...

    La difficulté avec ce genre de code, c'est que vous avez un état "global" qui doit entre cohérent entre clients et serveur et plus seulement un état global réduit aux variables d'un code qui s'exécute gentiment dans son coin.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre éclairé Avatar de RowanMayfair
    Femme Profil pro
    Développeuse Freelance
    Inscrit en
    Mars 2019
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 48
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeuse Freelance

    Informations forums :
    Inscription : Mars 2019
    Messages : 247
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    ah ben oui mais... il faut définir un protocole entre serveur et client.
    Par exemple, si vous écrivez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            for client in clients_a_lire :
                if client not in clients_sockets :
                    client.send(b"Bienvenue sur le Tchat")
                    n = client.recv(1024)
                    n = n.decode()
                    clients_sockets.setdefault(connexion_avec_client,n)
    vous supposez qu'après avoir ouvert la connexion, le client attend gentiment le message de bienvenue du serveur pour lui expédier la chaine de caractère qui permettra d'identifier le client.

    (...)

    - W
    En effet, cette étape là déjà ne fonctionne pas correctement. Le message de bienvenue du serveur ne s'affiche pas sur le client. Par contre, le serveur prend bien le premier message du client comme variable n, c'est à dire son nom. Ou presque, parce que le pour le 2ème client il a pris les 2 premiers messages comme identifiant.

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 754
    Par défaut
    Citation Envoyé par RowanMayfair Voir le message
    Ou presque, parce que le pour le 2ème client il a pris les 2 premiers messages comme identifiant.
    Ça c'est une autre specificité de la programmation réseau.
    Vous pensez "messages" en croyant que les .send d'un côte doivent, de l'autre côte, correspondre aux .recv...

    Alors qu'en fait, TCP/IP peut très bien retourner le début de ce qui a été expédié par un .send ou le contenu expédié par plusieurs .send pour un seul .recv. La seule chose que vous garantit la couche transport (le T dans TCP), c'est que les bytes seront, s'ils arrivent, reçus dans le même ordre qu'ils ont été expédiés.

    Et pour avoir des "messages", il va falloir découper ce flot de bytes pour délimiter ce qu'on pourra appeler "message". Histoire de s'assurer qu'on a tout reçu avant d'en faire quelque chose et de ne pas bouffer un bout du message suivant.

    Par exemple, dans votre cas, vous échangez des "lignes".

    Et pour découper le message en lignes, s'assurer que ce que vous avez reçu se termine bien par "fin de ligne" ('\r\n' ou '\n' par exemple) et de l'expédier explicitement - ce que vous n'expédiez pas n'arrivera jamais.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [Wamp] Réalisation mini chat
    Par levirus93700 dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 13
    Dernier message: 05/05/2008, 08h58
  2. [AJAX] Mini-Chat Basique
    Par foester dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 10/08/2007, 14h45
  3. Mini-chat en PHP
    Par azmodai dans le forum Langage
    Réponses: 10
    Dernier message: 25/07/2007, 16h38
  4. Mini Chat - sémaphores et mémoire partagée
    Par highman dans le forum Réseau
    Réponses: 4
    Dernier message: 02/04/2007, 21h54
  5. [Winsock] Quel est le port pour un mini-chat
    Par Jihnn dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 12/02/2007, 03h20

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