Langage Python: Exemple de jeu en réseau: le morpion
Présentation du projet
Notion de réseau
Tout d'abord, nous allons voir comment établir une communication entre deux machines seulement. L'une et l'autre pourront s'échanger des messages à tour de rôle, mais l'une de ces machines jouera le rôle d'un logiciel serveur, alors que l'autre se comportera comme un logiciel client.
Le serveur
Le logiciel serveur fonctionne en continu, sur un ordinateur dont l'identité est définie sur le réseau grâce à une adresse IP. Il guette en permanence l'arrivée de requêtes expédiées par les clients potentiels en direction de cette adresse, par l'intermédiaire d'un port de communication bien déterminé. Pour ce faire, le script correspondant doit mettre en oeuvre un objet logiciel associé à ce port, que l'on appelle un socket ou connecteur réseau.
Pour savoir l'adresse IP de votre ordinateur, ouvrez une invite de commande MS-DOS (Windows) ou le Terminal (OSX) et taper: ipconfig /all
(pour windows) ou ifconfig
(pour OSX)
Le client
Au départ d'une autre machine, le logiciel client tente d'établir la connexion en émettant une requête appropriée. Cette requête est un message qui est confié au réseau, un peu comme on confie une lettre à la Poste. Le réseau pourrait en effet acheminer la requête vers n'importe quelle autre machine, mais une seule est visée : pour que la destination visée puisse être atteinte, la requête contient dans son en-tête l'indication de l'adresse IP et du port de communication destinataires.
Lorsque la connexion est établie avec le serveur, le client lui assigne lui-même l'un de ses propres ports de communication. A partir de ce moment, on peut considérer qu'un canal privilégié relie les deux machines, comme si on les avait connectées l'une à l'autre par l'intermédiaire d'un fil (les deux ports de communication respectifs jouant le rôle des deux extrémités de ce fil). L'échange d'informations proprement dit peut commencer.
Différents types de sockets
Les sockets peuvent mettre en oeuvre deux techniques de communication différentes et complémentaires:- celle des paquets (que l'on appelle aussi des datagrammes), très largement utilisée sur l'internet
- celle de la connexion continue, ou stream socket, qui est un peu plus simple.
Exemple: Création d'une communication
On commence par le logiciel serveur:
import socket
from tkinter import *
from tkinter.messagebox import *
def connexion():
global connexion_avec_client, infos_connexion, connexion_principale
connexion_principale = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connexion_principale.bind((HOST.get(), PORT.get()))
connexion_principale.listen(5)
print("Le serveur écoute à présent sur le port {}".format(PORT.get()))
connexion_avec_client, infos_connexion = connexion_principale.accept()
dialogue()
def envoyer(message):
message=message.encode()
connexion_avec_client.send(message)
def recevoir():
msg_recu = connexion_avec_client.recv(1024)
msg_recu=msg_recu.decode()
return msg_recu
def dialogue():
while 1:
msg_recu=recevoir()
print(msg_recu)
message = input("Entrez votre message: ")
print(message)
envoyer(message)
print("Fermeture de la connexion")
connexion_avec_client.close()
connexion_principale.close()
# Création de la fenêtre principale (main window)
Mafenetre = Tk()
Mafenetre.title('Mise en réseau - Serveur')
# Cadre1 : paramètres serveur
cadre1 = Frame(Mafenetre,borderwidth=2,relief=GROOVE)
cadre1.grid(row=0,column=0,padx=5,pady=5,sticky=W+E)
Label(cadre1, text = "Hôte").grid(row=0,column=0,padx=5,pady=5,sticky=W)
HOST = StringVar()
HOST.set('127.0.0.1')
Entry(cadre1, textvariable= HOST).grid(row=0,column=1,padx=5,pady=5)
Label(cadre1, text = "Port").grid(row=1,column=0,padx=5,pady=5,sticky=W)
PORT = IntVar()
PORT.set(50026)
Entry(cadre1, textvariable= PORT).grid(row=1,column=1,padx=5,pady=5)
ButtonConnexion = Button(cadre1, text ='Ouvrir le serveur',command=connexion)
ButtonConnexion.grid(row=0,column=2,rowspan=2,padx=5,pady=5)
Mafenetre.mainloop()
Ensuite le logiciel client:
import socket
from tkinter import *
from tkinter.messagebox import *
def connexionserveur():
global connexion_avec_serveur
connexion_avec_serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connexion_avec_serveur.connect((HOST.get(), PORT.get()))
print("Connexion établie avec le serveur sur le port {}".format(PORT.get()))
dialogue()
def envoyer(message):
message=message.encode()
connexion_avec_serveur.send(message)
def recevoir():
msg_recu = connexion_avec_serveur.recv(1024)
msg_recu=msg_recu.decode()
return msg_recu
def dialogue():
while 1:
message = input("Entrez votre message: ")
print(message)
envoyer(message)
msg_recu=recevoir()
print(msg_recu)
print("Fermeture de la connexion")
connexion_avec_serveur.close()
# Création de la fenêtre principale (main window)
Mafenetre = Tk()
Mafenetre.title('Mise en réseau - Client')
# Cadre1 : paramètres serveur
cadre1 = Frame(Mafenetre,borderwidth=2,relief=GROOVE)
cadre1.grid(row=0,column=0,padx=5,pady=5,sticky=W+E)
Label(cadre1, text = "Hôte").grid(row=0,column=0,padx=5,pady=5,sticky=W)
HOST = StringVar()
HOST.set('127.0.0.1')
Entry(cadre1, textvariable= HOST).grid(row=0,column=1,padx=5,pady=5)
Label(cadre1, text = "Port").grid(row=1,column=0,padx=5,pady=5,sticky=W)
PORT = IntVar()
PORT.set(50026)
Entry(cadre1, textvariable= PORT).grid(row=1,column=1,padx=5,pady=5)
ButtonConnexion = Button(cadre1, text ='Connexion au serveur',command=connexionserveur)
ButtonConnexion.grid(row=0,column=2,rowspan=2,padx=5,pady=5)
Mafenetre.mainloop()
Se mettre par deux, l'un lance le serveur en renseignant sa propre adresse IP et un port de son choix (entre 49152 et 65535). L'autre lance le client en renseignant l'adresse IP du serveur et le port choisi par le serveur.
- En modifiant les programmes précédents, créer deux boutons dans le logiciel client ainsi que deux boutons dans le logiciel serveur comme ci-dessous;
- Associer aux boutons du logiciel client deux fonctions permettant de mettre en vert les boutons du logiciel client ainsi que les boutons respectifs du logiciel serveur. Pour changer la couleur d'un bouton nommé bouton1, il suffit d'écrire:


bouton1.configure(bg="green")