Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Serveur reseau et python

7 réponses
Avatar
Manu
Bonjour j'ai ecrit un petit client et un serveur grace au module socket
et select. L'idee est la suivant : je veux pouvoir updater dynamiquement
tous les clients connectes au serveur quand un evenement se passe sur
le serveur. Potentiellement cet evenement peut venir des clients( ca
ressemble a serveur chat et ses clients )
Mon probleme est que les clients sont toujours en attente de donnees et
l'appel a la fonction select ne va jamais bloque a cause des socket qui
sont disponible pour ecrire.

Comment peut on gerer ca et eviter que le serveur parte dans un boucle
while 1?
code:
<Server>
import socket, select
import thread, random
import time

def GenerateMsg():
while 1:
Q.append(str(random.randint(0,100)))
time.sleep(2)

myHostname = "localhost"
myPort = 1000
myBufSize = 1024
myBacklog = 5

serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind((myHostname,myPort))
serverSocket.listen(myBacklog)
print "listening..."
peers = [serverSocket]
Q = ['test']
thread.start_new_thread(GenerateMsg,())
while 1:
ready_to_read , ready_to_write , exceptions = select.select( peers
, peers ,[])
print "Select"
if ready_to_read:
for client in ready_to_read:
if client == serverSocket:
peer,addr = serverSocket.accept()
peers.append(peer)
print "Client connected"
else:
data = client.recv(myBufSize)
print data
if Q:
if ready_to_write:
for client in ready_to_write:
data = Q[0]
client.send(data)
Q.remove(data)

<client>
from socket import socket,AF_INET,SOCK_STREAM



myHostname = "localhost"
myPort = 1000
myBufSize = 1024

clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((myHostname,myPort))
print "Connected"
clientSocket.send("I am connecting ")
print "Request sent"
while 1:
data = clientSocket.recv(myBufSize)
if not data:
break
print data

7 réponses

Avatar
Sébastien Ramage
Salut!

Je ne suis pas certain d'avoir bien saisi ton problème mais si le
soucis c'est que le client ne peut pas envoyer de données parce qu'il
est en attente alors il faut simple créer 2 threads, un pour l'envoi
des données et pour la réception








Bonjour j'ai ecrit un petit client et un serveur grace au module socket
et select. L'idee est la suivant : je veux pouvoir updater dynamiquement
tous les clients connectes au serveur quand un evenement se passe sur
le serveur. Potentiellement cet evenement peut venir des clients( ca
ressemble a serveur chat et ses clients )
Mon probleme est que les clients sont toujours en attente de donnees et
l'appel a la fonction select ne va jamais bloque a cause des socket qui
sont disponible pour ecrire.

Comment peut on gerer ca et eviter que le serveur parte dans un boucle
while 1?
code:
<Server>
import socket, select
import thread, random
import time

def GenerateMsg():
while 1:
Q.append(str(random.randint(0,100)))
time.sleep(2)

myHostname = "localhost"
myPort = 1000
myBufSize = 1024
myBacklog = 5

serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind((myHostname,myPort))
serverSocket.listen(myBacklog)
print "listening..."
peers = [serverSocket]
Q = ['test']
thread.start_new_thread(GenerateMsg,())
while 1:
ready_to_read , ready_to_write , exceptions = select.select( peers
, peers ,[])
print "Select"
if ready_to_read:
for client in ready_to_read:
if client == serverSocket:
peer,addr = serverSocket.accept()
peers.append(peer)
print "Client connected"
else:
data = client.recv(myBufSize)
print data
if Q:
if ready_to_write:
for client in ready_to_write:
data = Q[0]
client.send(data)
Q.remove(data)

<client>
from socket import socket,AF_INET,SOCK_STREAM



myHostname = "localhost"
myPort = 1000
myBufSize = 1024

clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((myHostname,myPort))
print "Connected"
clientSocket.send("I am connecting ")
print "Request sent"
while 1:
data = clientSocket.recv(myBufSize)
if not data:
break
print data


Avatar
Manu
En effet j'etais pas tres clair! Le probleme est plutot du cote serveur
ou la fonction select n'est jamais bloquante .
Du coup le process serveur rentre dans une boucle infinie meme s'il n'a
rien a publier.



Salut!

Je ne suis pas certain d'avoir bien saisi ton problème mais si le
soucis c'est que le client ne peut pas envoyer de données parce qu'il
est en attente alors il faut simple créer 2 threads, un pour l'envoi
des données et pour la réception








Bonjour j'ai ecrit un petit client et un serveur grace au module socket
et select. L'idee est la suivant : je veux pouvoir updater dynamiquement
tous les clients connectes au serveur quand un evenement se passe sur
le serveur. Potentiellement cet evenement peut venir des clients( ca
ressemble a serveur chat et ses clients )
Mon probleme est que les clients sont toujours en attente de donnees et
l'appel a la fonction select ne va jamais bloque a cause des socket qui
sont disponible pour ecrire.

Comment peut on gerer ca et eviter que le serveur parte dans un boucle
while 1?
code:
<Server>
import socket, select
import thread, random
import time

def GenerateMsg():
while 1:
Q.append(str(random.randint(0,100)))
time.sleep(2)

myHostname = "localhost"
myPort = 1000
myBufSize = 1024
myBacklog = 5

serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind((myHostname,myPort))
serverSocket.listen(myBacklog)
print "listening..."
peers = [serverSocket]
Q = ['test']
thread.start_new_thread(GenerateMsg,())
while 1:
ready_to_read , ready_to_write , exceptions = select.select( peers
, peers ,[])
print "Select"
if ready_to_read:
for client in ready_to_read:
if client == serverSocket:
peer,addr = serverSocket.accept()
peers.append(peer)
print "Client connected"
else:
data = client.recv(myBufSize)
print data
if Q:
if ready_to_write:
for client in ready_to_write:
data = Q[0]
client.send(data)
Q.remove(data)

<client>
from socket import socket,AF_INET,SOCK_STREAM



myHostname = "localhost"
myPort = 1000
myBufSize = 1024

clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((myHostname,myPort))
print "Connected"
clientSocket.send("I am connecting ")
print "Request sent"
while 1:
data = clientSocket.recv(myBufSize)
if not data:
break
print data





Avatar
Sébastien Ramage
oui et en fait c'est normal puisque cette méthode ne fait qu'informer
sur l'état du socket


si tu ne veux pas tourner en boucle comme ça, ça suppose que tu veux
attendre qqc et ce qqc c'est la réception de donnée sur le socket

à mon avis tu dois créé 2 threads comme je le disais plus haut
un 1er qui te servira à envoyer des données quand il faudra en
envoyer
et un 2e qui attendra de recevoir des données

et encore le 1er thread n'est pas obligatoire si , par exemple, tu
envoi des données uniquement après la réception de données auquel
cas le thread de réception peut très bien servir à envoyer des
données avant de retourner en réception


après tu peux te servir de select pour voir si tu peux envoyer des
données ou non (encore que je n'ai pas vraiment compris l'utilité de
select...)

Seb






En effet j'etais pas tres clair! Le probleme est plutot du cote serveur
ou la fonction select n'est jamais bloquante .
Du coup le process serveur rentre dans une boucle infinie meme s'il n'a
rien a publier.



Salut!

Je ne suis pas certain d'avoir bien saisi ton problème mais si le
soucis c'est que le client ne peut pas envoyer de données parce qu'il
est en attente alors il faut simple créer 2 threads, un pour l'envoi
des données et pour la réception








Bonjour j'ai ecrit un petit client et un serveur grace au module socket
et select. L'idee est la suivant : je veux pouvoir updater dynamiqueme nt
tous les clients connectes au serveur quand un evenement se passe sur
le serveur. Potentiellement cet evenement peut venir des clients( ca
ressemble a serveur chat et ses clients )
Mon probleme est que les clients sont toujours en attente de donnees et
l'appel a la fonction select ne va jamais bloque a cause des socket qui
sont disponible pour ecrire.

Comment peut on gerer ca et eviter que le serveur parte dans un boucle
while 1?
code:
<Server>
import socket, select
import thread, random
import time

def GenerateMsg():
while 1:
Q.append(str(random.randint(0,100)))
time.sleep(2)

myHostname = "localhost"
myPort = 1000
myBufSize = 1024
myBacklog = 5

serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind((myHostname,myPort))
serverSocket.listen(myBacklog)
print "listening..."
peers = [serverSocket]
Q = ['test']
thread.start_new_thread(GenerateMsg,())
while 1:
ready_to_read , ready_to_write , exceptions = select.select( pe ers
, peers ,[])
print "Select"
if ready_to_read:
for client in ready_to_read:
if client == serverSocket:
peer,addr = serverSocket.accept()
peers.append(peer)
print "Client connected"
else:
data = client.recv(myBufSize)
print data
if Q:
if ready_to_write:
for client in ready_to_write:
data = Q[0]
client.send(data)
Q.remove(data)

<client>
from socket import socket,AF_INET,SOCK_STREAM



myHostname = "localhost"
myPort = 1000
myBufSize = 1024

clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((myHostname,myPort))
print "Connected"
clientSocket.send("I am connecting ")
print "Request sent"
while 1:
data = clientSocket.recv(myBufSize)
if not data:
break
print data







Avatar
Pierre Quentel
Bonjour,

La syntaxe de select est
ready_to_read,ready_to_write,exceptions =

select.select(potential_readers,potential_writers,potential_errs,timeout)

La plupart du temps, quand on teste une socket pour voir si on peut lui
envoyer quelque chose, la réponse est oui. Donc si tu mets une liste
non vide de sockets dans potential_writers, tu vas presque toujours
avoir une liste non vide dans ready_to_write, et tu entres dans la
boucle. S'il n'y a rien à envoyer (le tableau Q est vide) il ne se
passera rien, et tu reviens faire un select. Résultat, ta CPU est
prise à 99,9% dans une boucle qui ne fait rien

La solution est simple : il ne faut mettre les clients dans
potential_writers que si tu as quelque chose à écrire, c'est-à-dire
si le tableau Q n'est pas vide

En plus, il faut mettre un timeout. Sinon, tant que rien ne se passe
(aucun nouveau client ne cherche à se connecter, aucun client
connecté n'envoie de données), on reste dans select() jusqu'à la St
Glinglin. En mettant un timeout à 1 seconde, si rien n'a bougé on
sort de la boucle select au bout d'une seconde. Comme il n'y a rien
dans les tableaux ready_to_x, on ne fait rien, mais au moins pendant la
seconde en question, on n'a pratiquement rien consommé en temps
machine

Enfin, s'il y a des clients dans ready_to_read il faut faire un
try/except sur client.recv pour détecter les déconnections des
clients (fermeture de la fenêtre du client par exemple) et ne pas
planter le serveur

Voilà ce que ça donne ; j'ai ajouté l'envoi d'un message par le
client quand il a reçu quelque chose

---- serveur -----

import socket, select
import thread, random
import time

def GenerateMsg():
while 1:
Q.append(str(random.randint(0,100)))
time.sleep(2)

myHostname = "localhost"
myPort = 1000
myBufSize = 1024
myBacklog = 5

serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind((myHostname,myPort))
serverSocket.listen(myBacklog)
print "listening..."
peers = []
Q = ['test']
thread.start_new_thread(GenerateMsg,())
while 1:
# test incoming connections
if Q:
potential_writers = peers
else:
potential_writers = []
ready_to_read , ready_to_write , exceptions =
select.select([serverSocket]+peers,potential_writers,peers,1)
for client in exceptions:
ready_to_read.remove(client)
ready_to_write.remove(client)
peers.remove(client)
if ready_to_read:
for client in ready_to_read:
if client == serverSocket:
peer,addr = serverSocket.accept()
peers.append(peer)
print "Client connected"
else:
try:
data = client.recv(myBufSize)
print data
except:
print '%s is disconnected' %client
peers.remove(client)
if ready_to_write:
for client in ready_to_write:
data = Q[0]
client.send(data)
print 'sending %s to %s' %(data,client)
Q.remove(data)
---------------------------

---- client ----
from socket import socket,AF_INET,SOCK_STREAM

myHostname = "localhost"
myPort = 1000
myBufSize = 1024

clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((myHostname,myPort))
print "Connected"
clientSocket.send("I am connecting ")
print "Request sent"
while 1:
data = clientSocket.recv(myBufSize)
if not data:
break
print 'receiving',data
clientSocket.send('i am %s' %clientSocket)
------------------------
Avatar
swell
C'est parfait , merci Pierre , c'etait effectivement le probleme que
j'avais.
Je voudrais savoir si tu avais des recommandations supplementaires a me
faire sachant que mon serveur fera plutot du calcul que des accees au
fichier. C'est une des raisons pour lesquelles je n'ai pas 'encore'
regarder asynchore qui me semble tres bien mais plutot dans le cadre
d'acces a des donnees disques. Rajouter un compartiment threade au
dessus de ce serveur devrait faire l'affaire en terme de gestion du
nombre de clients potentiels.
Je vais egalement maintenant regarde pour faire un petit protocole
d'echange entre mes clients et mon serveur. Je pensais utiliser cPickle
, qu'en penses tu?

Merci

Manu
Avatar
Pierre Quentel
Bonjour,

L'avantage avec les threads c'est que si un client a fait une requête
dont le traitement prend du temps, les requêtes d'autres clients qui
arrivent pendant le traitement seront servies tout de suite. Par contre
la programmation des threads demande pas mal d'habitude, et le
basculement incessant d'un thread à l'autre consomme de la ressource :
au total les serveurs asynchrones sont plus rapides que leurs
équivalents multi thread

Pour le protocole, sans savoir exactement le type d'infos que tu veux
échanger, l'utilisation de cPickle est effectivement assez classique
pour transporter des données. A noter qu'il est souvent utile
d'envoyer d'abord la longueur des données qu'on envoie avant les
données elles-mêmes, ça rend la programmation du protocole plus
facile

A+
Pierre
Avatar
swell
Bonjour ,
Merci pour toutes ces infos qui m'ont beaucoup aides ( si ce n'est
pas pour dire tout fait :) ). En fait je suis en train d'ecrire un
serveur qui devra distribuer des informations lie a du calcul. En gros
des messages d'alerte qu'un evenement est arrive ( cette partie je
verrai plus tard , moteur prolog, correlation d'evenement, ... , python
est tellement vaste que ce n'est pas les methodes qui manqueront ici
aussi ) , un etat ( l'heure par exemple ce sera le premier type d'infos
que je veux que tout mes clients connaissent et bien sur un heartbeat )
. Ce sera 'jamais' des donnees lourdes ( type fichier , etc ) mais des
donnes calculees ou des etats. Potentiellement le serveur peut faire
beaucoup de calcul mais n'enverra jamais des donnees tres lourdes ( je
pense que ce sera quelques dizaine octets tout au plus )

Pierre aurait tu aussi des recommandations sur le type de proticole a
utiliser?

Merci
Manu