问题
I'm trying to learn asyncore module. So I decided to develop a chat program. I have to listen the network and broadcast udp packages same time. But problem is while user typing a message, user cannot see other messages that sent by another users. What should I do? My code:
#!/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:")
回答1:
The raw_input
call is blocking, but you can use asyncore on it too.
You need to add an third player i.e. like this:
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)
回答2:
#!/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()
Please see the following useage:
$ python ChatManager.py
[*] Listener - __init__ - create a socket
[*] Listener - __init__ - bind socket address
[*] Listener - __init__ - listen socket on 127.0.0.1:4444
Please make a connection to char server with:
$ nc -v 127.0.0.1 4444
And then, you can chat with the server on terminal.
来源:https://stackoverflow.com/questions/7312977/asyncore-loop-and-raw-input-problem