Bonne questions, voici une épave ébauche de serveur sans thread qui peux prendre plusieurs clients en gardant les connexion ouvertent.
class Server:
def __init__(self):
self.sock = socket.socket()
self.sock.setblocking(False) # rend la socket non-blocante.
self.sock.bind(("127.0.0.1", 7777))
self.sock.listen(5)
self.clients = []
def run(self):
while True:
try:
sock_client, addr_info = self.sock.accept()
except BlockingIOError:
pass # Personne veux se connecter, pas grave, je m'occupe des clients.
else:
sock_client.setblocking(False)
self.clients.append(sock_client)
for client in self.clients:
try:
print(client.recv(50))
except BlockingIOError:
pass # Le clients n'envoie rien pas grave, je passe à l'autre.
else:
try:
client.send(b"Coucou")
except BrokenPipeError: # Le client à fermé la connection
self.clients.remove(client) # on le gicle de la liste
sleep(0.25) # pour pas crammer le cpu
def __del__(self):
self.sock.close()
class Client:
def __init__(self, msg):
self.sock = socket.socket()
self.sock.connect(("127.0.0.1", 7777))
for i in range(10):
self.sock.send(bytes('{} ({})'.format(msg, i), 'utf-8'))
print(self.sock.recv(7))
self.sock.close()
# Bon là les thread c'est juste pour simuler
# les gonz qui se connectent. Tu peut trés bien
# mettre les client ds un autre shell sans les thread
from threading import Timer
Timer(1, Client, args=("salut",)).start()
Timer(1, Client, args=("le",)).start()
Timer(1, Client, args=("monde",)).start()
server = Server()
server.run()
]]>De plus, tu parles du champ Content-length, celui-ci n’est pas obligatoire dans le cas d’un serveur qui fermeraient les connections (Section 4.4 ). C’est également sans parler de la mécanique de messages Chunked. Bien sûr que pour des raisons de performance (et c’est pas forcement le cas article), on ne ferme pas le socket à la fin de la réponse, rien ne l’en empêche de le faire, c’est purement un choix technique et/ou une configuration sur le serveur.
Il est également intéressant de montrer que le protocole avait été conçu comme un protocole synchrone (requête puis réponse) mais qu’au final la plupart des implémentations ne le sont pas. Ce qui permet de tricher en envoyant la réponse avant même d’avoir reçu la requête Article récent décrivant la découverte.
]]>@policier moustachu: on l’a sur le blog.
]]># On ferme la connexion : le protocole HTTP est stateless,
# c’est à dire qu’il n’y a pas de maintien d’un état
# côté client ou serveur et chaque requête est indépendante
# de toutes les autres.
Presque ;-). Je chipotte, mais justement en HTTP 1.1 c’est plus sioux. Au niveau HTTP en effet, les requêtes sont indépendantes. La session est gérée (ou pas !) au niveau de l’application par divers moyens, et les fameux cookies sont un des moyens permettant de garder l’état pour savoir qui est qui et recoller les bouts.
Mais au niveau TCP, ce n’est heureusement pas stateless. Donc après la réponse, le serveur ne fait pas un close() sur la socket TCP, et le client non plus. Cela permet d’envoyer plusieurs requetes HTTP dans la même connexion TCP.
Pourquoi ça ? Et bien pour des raisons de perf. L’ouverture d’une connexion TCP a un coût (syn, ack, synack) et il est plus rapide de garder les tuyaux ouverts entre un client et le serveur web, une page page web étant souvent constituée de dizaines de ressources demandant chacune un appel HTTP. De plus, cela limite le nombre de connexion TCP en //, ce qui a un coût au niveau de tous les équipements réseaux sur le chemin de votre requête (firewal, reverse proxy, …).
C’est pour cela que le header sur la taille de la réponse est obligatoire en HTTP 1.1, car le client doit savoir quand ça s’arrette. En HTTP 1.0, c’est facile, il lit jusqu’à qu’à recevoir un close() de la part du serveur. Mais en HTTP 1.1 la socket reste ouverte, donc le client doit lire jusqu’à x octets, ensuite la connexion reste ouverte pour envoyer une autre requête.
On peut même multiplexer plusieurs requêtes dans une même connexion TCP, c’est à dire que le client fait plusieurs demandes à la suite sans attendre la réponse de chacune, puis reçoit plusieurs réponses, au lieu de simplement sérialiser. C’est plus rock’n roll et pas toujours pris en charge (souvent désactivé dans les browser). Cela s’appelle le pipelining http.
]]>