Application serveur
Une application serveur est une application offrant des services à d’autres applications (locales ou distantes) appelées applications clientes.
1. Aperçu
L’application serveur est un programme à l’écoute de requêtes provenant de clients connectés au réseau. Cette application choisit sur quelle IP et quel port elle écoute les requêtes.
- Adresses IP d’écoute
-
Un serveur peut écouter via n’importe laquelle de ses adresses, dont en particulier :
-
127.0.0.1accessible uniquement en local : s’il écoute seulement sur127.0.0.1(localhost), alors il ne pourra être sollicité que par des clients locaux (résidant sur la même machine) -
0.0.0.0qui représentant toutes ses adresses (dont127.0.0.1).
-
- Port d’écoute
-
Le port est un entier identifiant le service. Les ports <1024 sont normalisés et réservés à des services internet bien connus (well-known ports). Ils sont définis dans le fichier
/etc/services. Une application sans droit particulier ne peut pas écouter sur un port <1024. C’est pourquoi ces ports sont appelés ports privilégiés.
Le couple (IP,port) s’appelle un network socket.
C’est un point d’entrée de service unique sur le réseau.
Un serveur digne de ce nom ne doit pas faire attendre ses clients, en étant par exemple monopolisé par un client accaparant.
2. Problème
On dispose d’un embryon d’application client/serveur :
#!/bin/env python3
from socket import *
host = "localhost"
port = 2074
buf = 1024 # taille du buffer
s_addr = (host,port)
UDPsock = socket(AF_INET,SOCK_DGRAM) # création du socket
UDPsock.bind(s_addr) # activation
while True:
data,c_addr = UDPsock.recvfrom(buf) # écoute
print(f"\nReçu {data} de {c_addr}")
UDPsock.close()
et
#!/bin/env python3
from socket import *
host = "localhost"
port = 2074
buf = 1024 # taille du buffer
s_addr = (host,port)
UDPsock = socket(AF_INET,SOCK_DGRAM) # création du socket
while True:
msg = input('>> ')
if not msg: break
data = bytes(msg,'utf-8')
print(f"Envoi de {data}")
UDPsock.sendto(data,s_addr) # envoi vers le serveur
UDPsock.close()
Question 1
Comprendre le fonctionnement de ces 2 programmes, et les tester en local.
Question 2
Paramétrer le client de façon à pouvoir spécifier au lancement (en argument de la ligne de commande) le serveur à atteindre. Tester ensuite le cas où le client et le serveur ne sont pas sur la même machine.
Question 3
On souhaite maintenant observer le comportement du serveur lorsque le traitement des requêtes prend du temps. On définit pour cela le protocole suivant :
-
si le serveur reçoit une requete dont le format est :
<entier> "<chaine 1>" "<chaine 2>"
alors le serveur écrit sur son écran :
"<chaine1>" envoyé par <adresse du client>
puis attend
entiersecondes avant d’écrire :"<chaine2>" envoyé par <adresse du client> il y a <entier> secondes
-
si la requête n’a pas le format précédent, le serveur écrit sur son écran :
requête incompréhensible de <adresse du client>
Exemple, le client envoie
10 "debut" "fin"
au serveur qui doit afficher :
"debut" envoyé par 10.0.0.1
puis attendre 10 secondes, puis afficher :
"fin" envoyé par 10.0.0.1 il y a 10 secondes
Autre exemple, le client envoie :
10 debut fin
au serveur qui doit afficher :
requête incompréhensible de 10.0.0.1
Question 4
On souhaite maintenant que le serveur ne fasse pas attendre inutilement ses clients.
A l’aide du module Python threading, réaliser un serveur qui traite équitablement ses clients.