Eh bien, j'essaie de construire un petit prgram python avec un socketserver censé envoyer des messages qu'il reçoit à tous les clients connectés. Je suis coincé, je ne sais pas comment stocker des clients sur le Serveride et je ne sais pas comment envoyer à plusieurs clients. Oh et, mon programme échoue à chaque fois que 1 client se connecte et chaque client envoie plus d'un message ...
Voici mon code jusqu'à présent: p>
print str(self.client_address[0])+' connected.' def handle(self): new=1 for client in clients: if client==self.request: new=0 if new==1: clients.append(self.request) for client in clients: data=self.request.recv(1024) client.send(data) class Host: def __init__(self): self.address = ('localhost', 0) self.server = SocketServer.TCPServer(self.address, EchoRequestHandler) ip, port = self.server.server_address self.t = threading.Thread(target=self.server.serve_forever) self.t.setDaemon(True) self.t.start() print '' print 'Hosted with IP: '+ip+' and port: '+str(port)+'. Clients can now connect.' print '' def close(self): self.server.socket.close() class Client: name='' ip='' port=0 def __init__(self,ip,port,name): self.name=name self.hostIp=ip self.hostPort=port self.s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.connect((self.hostIp, self.hostPort)) def reco(self): self.s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.connect((self.hostIp, self.hostPort)) def nick(self,newName): self.name=newName def send(self,message): message=self.name+' : '+message len_sent=self.s.send(message) response=self.s.recv(len_sent) print response self.reco() def close(self): self.s.close()
4 Réponses :
Vous voulez regarder Asyncore ici. Les opérations de socket que vous appelez du côté du client bloquent (ne vous revenez pas avant que certaines données soient reçues ou un délai d'attente opère), ce qui permet d'écouter des messages envoyés à partir de l'hôte et de laisser les instances client en faisant des données à envoyer à le même temps. Asyncore est censé résumer la boucle de vote basée sur le délai d'attente loin de vous.
Voici un code "Échantillon" - laissez-moi savoir si quelque chose n'est pas clair: p>
INFO:root:Creating host INFO:root:Creating clients INFO:Client ( Alice):Connecting to host at ('127.0.0.1', 51117) INFO:Client ( Bob):Connecting to host at ('127.0.0.1', 51117) INFO:Client ( Alice):Enqueued message: Hello, everybody! INFO:root:Looping INFO:Host:Accepted client at ('127.0.0.1', 55628) INFO:Host:Accepted client at ('127.0.0.1', 55629) INFO:Host:Broadcasting message: Hello, everybody! INFO:Client ( Alice):Received message: Hello, everybody! INFO:Client ( Bob):Received message: Hello, everybody!
Merci, ça ressemble à ce que je cherchais! Malheureusement, je n'ai pas réussi à le faire fonctionner à l'extérieur Main B>: j'ai ajouté asyncore.loop () à la fin de l'hôte .__ init __ () et mon objet hôte accepte les connexions clientes, mais cela ne fait pas t réagir aux messages envoyés ...
@ALEX: asyncore.loop () fonctionne pour toujours! Effectivement en l'appelant, vous dites: "J'ai terminé de contrôler le programme, de la main sur la boucle d'Asyncore afin qu'elle puisse gérer l'envoi / reçoit pour le reste de l'époque." Remarquez comment je fixe tout avant d'appeler asyncore.loop (). Qu'essayez-vous de le déplacer?
Eh bien, je ne veux pas courir quelques connexions définies, mais que l'hôte fonctionne et que les clients puissent connecter / envoyer des messages à tout moment. Merci pour votre temps!
@Alex: Si vous exécutez plusieurs instances d'interpréteur Python, vous pouvez le faire facilement. Main va toujours exécuter asyncore.loop () code> (c'est ce qui rend les répartiteurs réellement faire i> choses), mais vous pouvez casser le programme dans un hôte.py et un client. py, où vous passez le client l'adresse de l'hôte via
sys.argv code>.
Une solution plus complète peut essayer de garantir que les messages complets sont toujours envoyés et reçus, au lieu d'appliquer une petite taille de message et en espérant que les messages entrent dans le tampon réseau, etc.
Pourquoi utiliser Socketserver? Un client simple ne répond pas à vos besoins?
Cela ne bloquera-t-il pas d'autres clients de se connecter?
Pour prendre plusieurs clients simultanément, vous devrez ajouter socketserver.forkingmixin code> ou
threadingmixin code>. P>
Vous pouvez utiliser Serveur strong> p> SocketServer code>
aux messages de diffusion à tous les clients connectés. Cependant, la capacité ne se construit pas dans le code et devra être mis en œuvre en étendant certaines des classes déjà fournies. Dans l'exemple suivant, cela est implémenté en utilisant le ThreadingTCPServer code> et
StreamRequestHandler code> classes. Ils constituent une base sur laquelle construire, mais encore nécessiter quelques modifications pour permettre ce que vous essayez d'accomplir. La documentation doit aider à expliquer ce que chaque fonction, la classe et la méthode essaient de faire pour faire le travail.
#! /usr/bin/env python3
import argparse
import cmd
import pickle
import socket
import threading
def main():
"""Connect a chat client to a server and process incoming commands."""
parser = argparse.ArgumentParser(description='Execute a chat client demo.')
parser.add_argument('host', type=str, help='name of server on the network')
parser.add_argument('port', type=int, help='location where server listens')
arguments = parser.parse_args()
client = User(socket.create_connection((arguments.host, arguments.port)))
client.start()
class User(cmd.Cmd, threading.Thread):
"""Provide a command interface for internal and external instructions."""
prompt = '>>> '
def __init__(self, connection):
"""Initialize the user interface for communicating with the server."""
cmd.Cmd.__init__(self)
threading.Thread.__init__(self)
self.connection = connection
self.reader = connection.makefile('rb', -1)
self.writer = connection.makefile('wb', 0)
self.handlers = dict(print=print, ping=self.ping)
def start(self):
"""Begin execution of processor thread and user command loop."""
super().start()
super().cmdloop()
self.cleanup()
def cleanup(self):
"""Close the connection and wait for the thread to terminate."""
self.writer.flush()
self.connection.shutdown(socket.SHUT_RDWR)
self.connection.close()
self.join()
def run(self):
"""Execute an automated message pump for client communications."""
try:
while True:
self.handle_server_command()
except (BrokenPipeError, ConnectionResetError):
pass
def handle_server_command(self):
"""Get an instruction from the server and execute it."""
source, (function, args, kwargs) = pickle.load(self.reader)
print('Host: {} Port: {}'.format(*source))
self.handlers[function](*args, **kwargs)
def preloop(self):
"""Announce to other clients that we are connecting."""
self.call('print', socket.gethostname(), 'just entered.')
def call(self, function, *args, **kwargs):
"""Arrange for a handler to be executed on all other clients."""
assert function in self.handlers, 'You must create a handler first!'
pickle.dump((function, args, kwargs), self.writer)
def do_say(self, arg):
"""Causes a message to appear to all other clients."""
self.call('print', arg)
def do_ping(self, arg):
"""Ask all clients to report their presence here."""
self.call('ping')
def ping(self):
"""Broadcast to all other clients that we are present."""
self.call('print', socket.gethostname(), 'is here.')
def do_exit(self, arg):
"""Disconnect from the server and close the client."""
return True
def postloop(self):
"""Make an announcement to other clients that we are leaving."""
self.call('print', socket.gethostname(), 'just exited.')
if __name__ == '__main__':
main()
J'ai eu un problème similaire résolu ici: serveur / client Code