Python 2.6 Chat Loop Issue. No puedo recibir y enviar simultáneamente

Estoy tratando de hacer un progtwig de chat de consola, pero tengo un problema con mi bucle. No puedo obtener información y recibir la información de otras personas al mismo tiempo. Si se envían dos mensajes o más desde un extremo, el otro extremo no puede recibir el siguiente mensaje hasta después de enviar uno. Soy bastante nuevo en Python, y estaba buscando un empujón en la dirección correcta. He pensado en subprocesos múltiples, pero eso es un poco fuera de mi scope atm. ¿Alguna otra idea?

import EncMod from socket import * #Get User Info Ip = raw_input('IP>>>') Port = int(raw_input('Port>>>')) User = raw_input('Username>>>') #Open Socket To Server EncCon = socket(AF_INET, SOCK_STREAM) EncCon.connect((Ip, Port)) print '\nStarting Chat....' print '\n\n\n' #Send/Receive Loop while 1: MsgOut = raw_input() if MsgOut: EncCon.send(MsgOut) MsgIn = EncCon.recv(1024) if MsgIn: print MsgIn EncCon.close() 

El marco Twisted puede utilizarse para ayudar a lograr esta tarea. El código que aparece a continuación inicia un servidor de chat al que los clientes pueden conectarse y comunicarse entre sí, según la configuración de la instancia del servidor. Puede hacer las modificaciones apropiadas para adaptarse a sus necesidades:

 from twisted.internet.protocol import Factory from twisted.protocols.basic import LineReceiver from twisted.internet import reactor class Chat(LineReceiver): def __init__(self, users): self.users = users self.name = None self.state = "GETNAME" def connectionMade(self): self.sendLine("What's your name?") def connectionLost(self, reason): if self.users.has_key(self.name): del self.users[self.name] def lineReceived(self, line): if self.state == "GETNAME": self.handle_GETNAME(line) else: self.handle_CHAT(line) def handle_GETNAME(self, name): if self.users.has_key(name): self.sendLine("Name taken, please choose another.") return self.sendLine("Welcome, %s!" % (name,)) self.name = name self.users[name] = self self.state = "CHAT" def handle_CHAT(self, message): message = "<%s> %s" % (self.name, message) for name, protocol in self.users.iteritems(): if ':' in message: self.exc(message.split(':')[0]) if protocol != self: protocol.sendLine(message) def exc(self, cmd): print cmd if cmd == 'who': for i in self.users: print i class ChatFactory(Factory): def __init__(self): self.users = {} # maps user names to Chat instances def buildProtocol(self, addr): return Chat(self.users) reactor.listenTCP(8123, ChatFactory()) reactor.run() 

El problema es que su llamada recv () se bloquea hasta que se reciben algunos datos, y mientras recv () está bloqueando, su progtwig no está comprobando si hay alguna entrada de stdin. La solución tradicional de un solo hilo para esto es configurar el socket a E / S sin locking (a través de EncCon.setblocking (Falso)) y luego tener el bloque de progtwig dentro de select () en su lugar. Pase tanto EncCon como stdin a select () (como parte de su argumento de lectura-socket-set) para que select () regrese cada vez que alguno de ellos tenga algunos datos para brindarle. (Tenga en cuenta que este método no funciona en Windows, ya que Windows no permite seleccionar () para bloquear en stdin: P)

El enhebrado no es tan difícil como cree, y dominarlo es una valiosa adición a su toolchest.

Simplemente cree una clase que sea una subclase de Thread y asegúrese de que tenga un método run (). luego crea una instancia de la clase y llama a su método start ().

Hacer que el hilo se detenga es más difícil de hacer bien. Lo mejor es establecer una bandera y asegurarse de verificarla regularmente en su bucle while, por lo tanto, necesita un tiempo de espera en su recv () de locking, de, por ejemplo, 1 segundo.

 from socket import * from threading import Thread #Get User Info Ip = raw_input('IP>>>') Port = int(raw_input('Port>>>')) User = raw_input('Username>>>') #Open Socket To Server EncCon = socket(AF_INET, SOCK_STREAM) EncCon.connect((Ip, Port)) print '\nStarting Chat....' print '\n<-------------------------------------------->\n\n' class ReceiveThread(Thread): def __init__(self, sock): Thread.__init__(self) self.sock = sock self.shouldstop = False def run(self): self.sock.settimeout(1) while not self.shouldstop: try: data = self.sock.read() print data except socket.timeout: continue def stop(self): self.shouldstop = True # start receive loop: r = ReceiveThread(EncCon).start() #Send Loop while 1: MsgOut = raw_input() if MsgOut: EncCon.send(MsgOut) if MsgOut == '.': r.stop() r.join() EncCon.close() 

Ahora, este progtwig todavía tiene el problema original de que sería imposible iniciar dos instancias, ya que no escucha, pero se conecta de inmediato. Pero eso, creo, no fue la parte principal de su pregunta.