Асинхронный цикл и проблема raw_input - PullRequest
7 голосов
/ 06 сентября 2011

Я пытаюсь выучить модуль asyncore. Поэтому я решил разработать программу чата. Я должен слушать сеть и транслировать пакеты udp одновременно. Но проблема в том, что когда пользователь печатает сообщение, он не может видеть другие сообщения, отправленные другими пользователями. Что я должен делать? Мой код:

#!/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:")

Ответы [ 2 ]

9 голосов
/ 06 сентября 2011

Вызов 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 голосов
/ 22 июня 2016
#!/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

Пожалуйста, установите соединение с сервером символов с:

$ nc -v 127.0.0.1 4444

И затем, вы можете общаться с сервером на терминале.

...