Ping …

Séance de révision réseau :

grâce à Maxence Klein, diapos commentées sur son site.

Una application client / serveur en Python ?

S’en suit un passage promis mais épineux, dans lequel on discute socket pour le réseau et Threading pour … et bien … créer plusieurs threads pour écouter le réseau ou envoyer des données via ces sockets, sur le client ou le serveur

On a présenté et testé un petit programme de discussion en réseau avec un client et un serveur dont les codes sont ci-dessous.

On s’est fortement inspiré du cours de Fabrice Sincère. Merci !


La séance a été enregistrée et peut être revue en cliquant sur « présentation » en bas de cette page (la page de connexion au salon virtuel).


Code du serveur :

import socket, sys, threading, time

# variables globales

# adresse IP et port utilisés par le serveur
HOST = ""
PORT = 52042

NOMBREJOUEUR = 2

dict_clients = {}  # dictionnaire des connexions clients
dict_pseudos = {}  # dictionnaire des pseudos
dict_messages = []

NOMBRE_PHRASES_MAX = 5

class ThreadClient(threading.Thread):
    '''dérivation de classe pour gérer la connexion avec un client'''
    
    def __init__(self, conn):

        threading.Thread.__init__(self)
        self.connexion = conn
        
        # Mémoriser la connexion dans le dictionnaire
        
        self.nom = self.getName() # identifiant du thread "<Thread-N>"
        dict_clients[self.nom] = self.connexion
        
        print("Connexion du client", self.connexion.getpeername(),self.nom ,self.connexion)
        
        message = bytes("Vous êtes connecté au serveur.\n","utf-8")
        self.connexion.send(message)
        
        
    def run(self):
        
        # Choix du pseudo    
        
        self.connexion.send(b"Entrer un pseudo :\n")
        # attente réponse client
        pseudo = self.connexion.recv(4096)
        pseudo = pseudo.decode(encoding='UTF-8')
        
        dict_pseudos[self.nom] = pseudo
        
        print("Pseudo du client", self.connexion.getpeername(),">", pseudo)
        
        message = b"Attente des autres clients...\n"
        self.connexion.send(message)
    
        # Réponse aux questions
       
        while True:
            
            try:
                # attente réponse client
                reponse = self.connexion.recv(4096)
                reponse = reponse.decode(encoding='UTF-8')
                message = dict_pseudos[self.nom] + ">" + reponse
                MessagePourTous(message)
                dict_messages.append(message)
                
            except:
                # fin du thread
                break
                
        print("\nFin du thread",self.nom)
        self.connexion.close()

def MessagePourTous(message):
    """ message du serveur vers tous les clients"""
    for client in dict_clients:
        dict_clients[client].send(bytes(message,"utf8"))
        
        
# Initialisation du serveur
# Mise en place du socket avec les protocoles IPv4 et TCP
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
try:
    mySocket.bind((HOST, PORT))
except socket.error:
    print("La liaison du socket à l'adresse choisie a échoué.")
    sys.exit()
print("Serveur prêt (port",PORT,") en attente de clients...")
mySocket.listen(5)


# len(dict_clients) -> nb de joueurs connectés

while len(dict_clients) < NOMBREJOUEUR:
    # Attente connexion nouveau client
    try:
        connexion, adresse = mySocket.accept()
    except:
        sys.exit()
    # Créer un nouvel objet thread pour gérer la connexion
    th = ThreadClient(connexion)
    # The entire Python program exits when no alive non-daemon threads are left
    th.setDaemon(1)
    th.start()
    

while len(dict_pseudos) < NOMBREJOUEUR:
    # on attend que tout le monde ait entré son pseudo
    pass


MessagePourTous("\nC'est parti !\n")

while len(dict_messages) < NOMBRE_PHRASES_MAX:
    pass

# Fin
MessagePourTous("\nFIN\nVous pouvez fermer l'application...\n")

# fermeture des sockets
for client in dict_clients:
    dict_clients[client].close()
    print("Déconnexion du socket", client)

input("\nAppuyer sur Entrée pour quitter l'application...\n")
# fermeture des threads (daemon) et de l'application

Code du client :

import socket, sys, threading

HOSTDEFAULT = "127.0.0.1" # ou "localhost"
HOST = input("Adresse IP du serveur ? ")
if HOST == "":
    HOST = HOSTDEFAULT
PORTDEFAULT = 52042
PORT = input("Numéro du port ? ")
if PORT == "":
    PORT = PORTDEFAULT
else:
    PORT = int(PORT)
    

class ThreadReception(threading.Thread):
    """objet thread gérant la réception des messages"""
    def __init__(self, conn):
        threading.Thread.__init__(self)
        self.connexion = conn  # réf. du socket de connexion

    def run(self):
        while True:
            try:
                # en attente de réception
                message_recu = self.connexion.recv(4096)
                message_recu = message_recu.decode(encoding='UTF-8')
                print(message_recu)
            except:
                # fin du thread
                break
            
        print("ThreadReception arrêté. Connexion interrompue.")
        self.connexion.close()

class ThreadEmission(threading.Thread):
    """objet thread gérant l'émission des messages"""
    def __init__(self, conn):
        threading.Thread.__init__(self)
        self.connexion = conn   # réf. du socket de connexion

    def run(self):
        while True:
            message_emis = input()
            try:
                # émission
                self.connexion.send(bytes(message_emis,'UTF-8'))
            except:
                # fin du thread
                break
            
        print("ThreadEmission E arrêté. Connexion interrompue.")
        self.connexion.close()

# Programme principal - Établissement de la connexion
# protocoles IPv4 et TCP
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
try:
    mySocket.connect((HOST, PORT))
except socket.error:
    print("La connexion a échoué.")
    sys.exit()

# Dialogue avec le serveur : on lance deux threads pour gérer
# indépendamment l'émission et la réception des messages
th_R = ThreadReception(mySocket)
th_R.start()
th_E = ThreadEmission(mySocket)
th_E.start()

Contenu de Fabrice Sincère sous licence CC BY-NC-SA 3.0

N'hésitez-pas à poser une question, ou faire avancer le schmilblick

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google

Vous commentez à l’aide de votre compte Google. Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.