2011-09-05 8 views
7

Sto cercando di imparare il modulo asyncore. Così ho deciso di sviluppare un programma di chat. Devo ascoltare la rete e trasmettere i pacchetti udp contemporaneamente. Ma il problema è che mentre un utente digita un messaggio, l'utente non può vedere altri messaggi inviati da altri utenti. Cosa dovrei fare? Il mio codice:Asyncore loop e raw_input problem

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

import asyncore 
import socket 

class Listener(asyncore.dispatcher): 
    def __init__(self, port): 
     asyncore.dispatcher.__init__(self) 
     self.port = port 
     self.create_socket(socket.AF_INET, socket.SOCK_DGRAM) 
     self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     self.bind(('', self.port)) 

    def handle_connect(self): 
     print "CONNECTED." 

    def handle_read(self): 
     data, addr = self.recvfrom(1024) 
     print str(addr) + " > " + data 

    def handle_write(self): 
     pass 

class Sender(asyncore.dispatcher): 
    def __init__(self, port): 
     asyncore.dispatcher.__init__(self) 
     self.buffer = "" 
     self.port = port 
     self.create_socket(socket.AF_INET, socket.SOCK_DGRAM) 
     self.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 
     self.bind(('',0)) 

    def handle_connect(self): 
     print "CONNECTED." 

    def handle_read(self): 
     pass 

    def handle_write(self): 
     if self.buffer != "": 
      sent = self.sendto(self.buffer, ('<broadcast>', self.port)) 
      self.buffer = self.buffer[sent:] 

    def handle_close(self): 
     self.close() 

    def serve_forever(self): 
     asyncore.loop(count = 10) 

if __name__ == "__main__": 
    Listener(50000) 
    sender = Sender(50000) 

    while True: 
     sender.serve_forever() 
     sender.buffer += raw_input("Message:") 
+0

Avete considerato [Twisted] (http://www.twistedmatrix.com)? –

+0

Mi piacerebbe risolvere questo problema usando asyncore se è possibile. – voiceofthesoul

+0

Puoi darmi una buona ragione per cui? –

risposta

9

La chiamata raw_input sta bloccando, ma è possibile utilizzare asyncore su di esso troppo. È necessario aggiungere un terzo giocatore cioè in questo modo:

class CmdlineClient(asyncore.file_dispatcher): 
    def __init__(self, sender, file): 
     asyncore.file_dispatcher.__init__(self, file) 
     self.sender = sender 

    def handle_read(self): 
     self.sender.buffer += self.recv(1024) 

import sys 
sender = Sender(50000) 
cmdline = CmdlineClient(sender, sys.stdin) 
+0

grazie, questa è la risposta che voglio :) – voiceofthesoul

+1

Sfortunatamente, è disponibile solo su Unix. – erickrf

0
#!/usr/bin/env python 
# -*- coding: utf8 -*- 

import asyncore 
import logging 
import sys 


logging.basicConfig(level=logging.DEBUG, 
        format='[*] %(name)s - %(funcName)16s - %(message)s') 


class ConsoleHandler(asyncore.file_dispatcher): 
    """Enable console interactive for socket read/write. 
    """ 
    def __init__(self, sender, file): 
     asyncore.file_dispatcher.__init__(self, file) 
     self.current_chat = sender 
     self.BUFSIZE = 1024 

    def handle_read(self): 
     self.current_chat.out_buffer += self.recv(self.BUFSIZE) 


class ChatManager(asyncore.dispatcher): 
    """Handle tcp in-connections, ex: send commands to targets. 
    """ 
    def __init__(self, _sock=None, _map=None): 
     self.logger = logging.getLogger('ChatManager') 
     self.BUFSIZE = 1024 

     asyncore.dispatcher.__init__(self, _sock, _map) 
     self.out_buffer = '' 

    def handle_read(self): 
     """Called when the asynchronous loop detects that a read() call on 
      the channel's socket will succeed.""" 
     data = self.recv(self.BUFSIZE) 
     self.logger.debug('%d bytes | client <- server' % len(data)) 
     print(data.strip()) 
     # self.send(data) 
     self.logger.debug('%d bytes | client -> server' % len(data)) 

    def handle_write(self): 
     """Called when the asynchronous loop detects that a writable 
      socket can be written. Often this method will implement the 
      necessary buffering for performance. For example: 
     """ 
     if self.out_buffer != "": 
      sent = self.send(self.out_buffer) 
      self.out_buffer = self.out_buffer[sent:] 

    def handle_error(self): 
     """Called when an exception is raised and not otherwise handled. 
      The default version prints a condensed traceback. 
     """ 
     self.logger.debug('socket exception') 

    def handle_close(self): 
     """Called when the socket is closed. 
     """ 
     self.close() 


class Listener(asyncore.dispatcher): 
    """Start a tcp listener (default: 127.0.0.1:4444), and wait for connections. 
     If a new connection, `ChatManager' will try to handle it. 
    """ 
    def __init__(self, addr=('127.0.0.1', 4444), max_connections=4): 
     self.logger = logging.getLogger('Listener') 

     asyncore.dispatcher.__init__(self) 
     self.logger.debug('create a socket') 
     self.create_socket(asyncore.socket.AF_INET, 
          asyncore.socket.SOCK_STREAM) 

     # socket reuse address 
     self.set_reuse_addr() 

     self.bind(addr) 
     self.logger.debug('bind socket address') 

     self.listen(max_connections) 
     self.logger.debug('listen socket on %s:%s' % addr) 

    def handle_accept(self): 
     client, caddr = self.accept() 
     self.logger.debug('client: %s:%s' % caddr) 
     self.logger.debug('Enter into ChatManager') 
     ConsoleHandler(ChatManager(client), sys.stdin) 


if __name__ == "__main__": 
    Listener() 
    asyncore.loop() 

vedere il seguente useage:

$ python ChatManager.py 
[*] Listener -   __init__ - create a socket 
[*] Listener -   __init__ - bind socket address 
[*] Listener -   __init__ - listen socket on 127.0.0.1:4444 

Si prega di effettuare una connessione a char server con:

$ nc -v 127.0.0.1 4444 

E quindi, puoi chattare con il server sul terminale.