2011-09-05 76 views
7

我在學習asyncore模塊。所以我決定開發一個聊天程序。我必須同時收聽網絡和廣播udp包。但問題出在用戶輸入消息時,用戶看不到其他用戶發送的其他消息。我該怎麼辦?我的代碼:異步循環和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() 

請看以下用途:

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

請爲char服務器的連接:

$ nc -v 127.0.0.1 4444 

然後,您可以在終端上與服務器聊天。