2011-09-05 10 views
7

私はasyncoreモジュールを学習しようとしています。だから私はチャットプログラムを開発することに決めました。私はネットワークとudpパッケージを同時に聞く必要があります。しかし、問題はユーザーがメッセージを入力している間、ユーザーは別のユーザーが送信した他のメッセージを見ることができません。私は何をすべきか?私のコード:Asyncoreループとraw_inputの問題

#!/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

あなたは[Twisted](http://www.twistedmatrix.com)を考えましたか? –

+0

可能であれば、asyncoreを使用してこの問題を解決したいと思います。 – voiceofthesoul

+0

なぜ私に正当な理由がありますか? –

答えて

9

raw_input呼び出しがブロックしているが、あなたはあまりにもそれにasyncoreを使用することができます。 にあなたはすなわち、このような第三のプレーヤーを追加する必要があります。

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

ありがとう、これは私が欲しい答えです:) – voiceofthesoul

+1

残念ながら、それは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() 

を次useageご覧ください。

$ nc -v 127.0.0.1 4444 

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

を持つchar型のサーバーへの接続を作成してください。

そして、端末のサーバとチャットできます。