Esempio n. 1
0
    def __init__(self, sock = None):
        """
            Initialise a base SocketMultiplexer that uses 'sock' as its
            ManagedSocket instantiator.
        """

        self._keep_running = False
        if sock is None:
            sock = ManagedSocket
        self._sock = sock
        self.eq = DeadEventQueue()
        self._alarm = None
        self._reads, self._writes = [], []
Esempio n. 2
0
class SocketMultiplexer(object):
    """
        Abstract socket multiplexer, useful for managing lots of sockets
        with a single thread.
        Inherit to create a multiplexed socket based application.
        You should only override the on***() callback methods.
    """

    # Setup optimised listen queue default
    # The maximum should be 128 by default under linux 2.0 and up
    # To check do a 'cat /proc/sys/net/core/somaxconn'
    LISTEN_QUEUE_MAXIMUM = socket.SOMAXCONN
    LISTEN_QUEUE_DEFAULT = min(16, socket.SOMAXCONN)

    class Deadlock(Exception):
        """
            This class represents the occurrence of a deadlock in the event
            processing system. (It would wait forever on nothing)
        """

    def __init__(self, sock = None):
        """
            Initialise a base SocketMultiplexer that uses 'sock' as its
            ManagedSocket instantiator.
        """

        self._keep_running = False
        if sock is None:
            sock = ManagedSocket
        self._sock = sock
        self.eq = DeadEventQueue()
        self._alarm = None
        self._reads, self._writes = [], []

    def startMultiplex(self):
        """
            Begin multiplexing non-blocking sockets.
            This call does not return, until either a deadlock exception occurs
            or stopMultiplex is called.
        """

        self._keep_running = True
        tick = None

        try:
            while self._keep_running:
                try:

                    # Handle the events system
                    if self.eq.nextEventTicks() is None:
                        tick = None
                    elif tick is None:
                        tick = time()
                    else:
                        newtick = time()
                        if newtick - tick > 0.0:
                            self.eq.elapseTime(newtick - tick)
                        tick = newtick
                        del newtick

                    # Guard against activity deadlocks
                    # They really shouldn't occur, but it is good practice to
                    # catch them.
                    if len(self._reads) + len(self._writes) == 0 and \
                            self.eq.nextEventTicks() is None:
                        raise SocketMultiplexer.Deadlock("No events left")

                    # Wait for activity
                    reads, writes, excepts = \
                        select(self._reads, self._writes, [],
                            self.eq.nextEventTicks())

                    # Handle the events system
                    # I know this isn't the nicest solution, but
                    # this is required to fix a nasty bug triggering over
                    # execution.
                    if self.eq.nextEventTicks() is None:
                        tick = None
                    elif tick is None:
                        tick = time()
                    else:
                        newtick = time()
                        if newtick - tick > 0.0:
                            self.eq.elapseTime(newtick - tick)
                        tick = newtick
                        del newtick

                except select_error, e:
                    if e.args[0] == errno.EINTR:
                        self.onSignal()
                        continue
                    raise e

                # Handle reads and writes
                for r in reads: r.handleRead()
                for w in writes: w.handleWrite()
        finally:
            self._keep_running = False

        return True

    def timeFlow(self):
        """
            Executes the flow of time.

            This function will be used in the future to
            prevent clock jumps and streamline the events system.
        """

    def stopMultiplex(self):
        """
            Stop multiplexing.
        """
        if not self._keep_running:
            return False
        self._keep_running = False
        return True

    def connect(self, ip, port, **keywords):
        """
            Initiate a client connection to the specified server.

            Additionally you can specify 'sock = <some class' in the
            function call to override the default socket instantiator.
            Any additional keywords shall be passed on to
            the socket constructor.
        """
        try:
            sock = keywords['sock']
            del keywords['sock']
        except KeyError:
            sock = self._sock
        new = sock(self, ip, port, **keywords)
        new.connect()
        return True

    def listen(self, ip, port,
            queue_length = None, **keywords):
        """
            Create a new socket that will start listening on
            the specified address.

            Additionally you can specify 'sock = <some class' in the
            function call to override the default socket instantiator.
            Any additional keywords shall be passed on to
            the socket constructor.
        """
        if queue_length == None:
            queue_length = SocketMultiplexer.LISTEN_QUEUE_DEFAULT
        try:
            sock = keywords['sock']
            del keywords['sock']
        except KeyError:
            sock = self._sock
        new = sock(self, ip, port, **keywords)
        if not new.listen(queue_length):
            return False
        return True

    def addReader(self, sock):
        """
            Add socket to the list of sockets watched for reading
        """
        if sock in self._reads:
            return False
        self._reads.append(sock)
        return True

    def delReader(self, sock):
        """
            Delete socket from the list of sockets watched for reading
        """
        try:
            self._reads.remove(sock)
        except ValueError:
            return False
        return True

    def addWriter(self, sock):
        """
            Add socket to the list of sockets watched for writing
        """
        if sock in self._writes:
            return False
        self._writes.append(sock)
        return True

    def delWriter(self, sock):
        """
            Delete socket from the list of sockets watched for writing
        """
        try:
            self._writes.remove(sock)
        except ValueError:
            return False
        return True

    def setAlarm(self, seconds):
        """
            Sets an alarm that will occur in 'seconds' time, seconds may be
            fractional. If seconds is None any pending alarm will be cancelled
        """

        if self._alarm is not None:
            self.eq.cancelEvent(self._alarm)
        if seconds is not None:
            self._alarm = DeferredCall(seconds, self.execAlarm)
            self.eq.scheduleEvent(self._alarm)
        return True

    def execAlarm(self):
        """
            Handler that executes the onAlarm() method.
        """
        self._alarm = None
        self.onAlarm()

    def onAlarm(self):
        """
            Called when the alarm set by setAlarm() occurs
        """

    def onSignal(self):
        """