Пример #1
0
class dispatcher(asyncore.dispatcher):
    connectChannel = None
    acceptChannel = None
    recvChannel = None

    def __init__(self, sock):
        # This is worth doing.  I was passing in an invalid socket which was
        # an instance of dispatcher and it was causing tasklet death.
        if not isinstance(sock, stdsocket.socket):
            raise StandardError("Invalid socket passed to dispatcher")
        asyncore.dispatcher.__init__(self, sock)

        # if self.socket.type == SOCK_DGRAM:
        #    self.dgramRecvChannels = {}
        #    self.dgramReadBuffers = {}
        #else:
        self.recvChannel = Channel(micro_send=True)
        self.readBufferString = ''
        self.readBufferList = []

        self.sendBuffer = ''
        self.sendToBuffers = []

        self.maxreceivebuf=65536

    def writable(self):
        if self.socket.type != SOCK_DGRAM and not self.connected:
            return True
        return len(self.sendBuffer) or len(self.sendToBuffers)

    def accept(self):
        if not self.acceptChannel:
            self.acceptChannel = Channel(micro_send=True)
        return self.acceptChannel.recv()

    def connect(self, address):
        asyncore.dispatcher.connect(self, address)
        # UDP sockets do not connect.

        if self.socket.type != SOCK_DGRAM and not self.connected:
            if not self.connectChannel:
                # Prefer the sender.  Do not block when sending, given that
                # there is a tasklet known to be waiting, this will happen.
                self.connectChannel = Channel(prefer_sender=True)
            self.connectChannel.recv()

    def send(self, data):
        self.sendBuffer += data
        micro_block()
        return len(data)

    def sendall(self, data):
        # WARNING: this will busy wait until all data is sent
        # It should be possible to do away with the busy wait with
        # the use of a channel.
        self.sendBuffer += data
        while self.sendBuffer:
            micro_block()
        return len(data)

    def sendto(self, sendData, sendAddress):
        waitChannel = None
        for idx, (data, address, channel, sentBytes) in enumerate(self.sendToBuffers):
            if address == sendAddress:
                self.sendToBuffers[idx] = (data + sendData, address, channel, sentBytes)
                waitChannel = channel
                break
        if waitChannel is None:
            waitChannel = Channel(micro_send=True)
            self.sendToBuffers.append((sendData, sendAddress, waitChannel, 0))
        return waitChannel.recv()

    # Read at most byteCount bytes.
    def recv(self, byteCount):
        self.maxreceivebuf=byteCount
        if len(self.readBufferString) < byteCount:
            # If our buffer is empty, we must block for more data we also
            # aggressively request more if it's available.
            if len(self.readBufferString) == 0 or self.recvChannel.ch.balance > 0:
                self.readBufferString += self.recvChannel.recv()
        # Disabling this because I believe it is the onus of the application
        # to be aware of the need to run the scheduler to give other tasklets
        # leeway to run.
        # stackless.schedule()
        ret = self.readBufferString[:byteCount]
        self.readBufferString = self.readBufferString[byteCount:]
        return ret

    def recvfrom(self, byteCount):
        ret = ""
        address = None
        self.maxreceivebuf=byteCount
        return self.recvChannel.recv()

    def close(self):
        asyncore.dispatcher.close(self)
        self.connected = False
        self.accepting = False
        self.sendBuffer = ''  # breaks the loop in sendall

        # Clear out all the channels with relevant errors.

        if self.acceptChannel is not None:
            while self.acceptChannel and self.acceptChannel.ch.balance < 0:
                self.acceptChannel.send_exception(error, 9, 'Bad file descriptor')
        if self.connectChannel is not None:
            while self.connectChannel and self.connectChannel.ch.balance < 0:
                self.connectChannel.send_exception(error, 10061, 'Connection refused')
        if self.recvChannel is not None:
            while self.recvChannel and self.recvChannel.ch.balance < 0:
                # The closing of a socket is indicted by receiving nothing.  The
                # exception would have been sent if the server was killed, rather
                # than closed down gracefully.
                self.recvChannel.ch.send("")
                #self.recvChannel.send_exception(error, 10054, 'Connection reset by peer')

    # asyncore doesn't support this.  Why not?
    def fileno(self):
            # XXX: self.socket.fileno() raises a Bad file descriptor error.
            #      Therefore, we're using _fileno as a hack. This has to be
            #      cleaned.
            # return self.socket.fileno() 
        return self._fileno

    def handle_accept(self):
        if self.acceptChannel and self.acceptChannel.ch.balance < 0:
            currentSocket, clientAddress = asyncore.dispatcher.accept(self)
            currentSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
            # Give them the asyncore based socket, not the standard one.
            currentSocket = self.wrap_accept_socket(currentSocket)
            self.acceptChannel.send((currentSocket, clientAddress))

    # Inform the blocked connect call that the connection has been made.
    def handle_connect(self):
        if self.socket.type != SOCK_DGRAM and self.connectChannel is not None:
            self.connectChannel.send(None)

    # Asyncore says its done but self.readBuffer may be non-empty
    # so can't close yet.  Do nothing and let 'recv' trigger the close.
    def handle_close(self):
        pass

    # Some error, just close the channel and let that raise errors to
    # blocked calls.
    def handle_expt(self):
        self.close()

    def handle_read(self):
        try:
            if self.socket.type == SOCK_DGRAM:
                ret, address = self.socket.recvfrom(self.maxreceivebuf)
                self.recvChannel.send((ret, address))
            else:
                ret = asyncore.dispatcher.recv(self, self.maxreceivebuf)
                # Not sure this is correct, but it seems to give the
                # right behaviour.  Namely removing the socket from
                # asyncore.
                if not ret:
                    self.close()
                self.recvChannel.send(ret)
        except stdsocket.error, err:
            # XXX Is this correct?
            # If there's a read error assume the connection is
            # broken and drop any pending output
            if self.sendBuffer:
                self.sendBuffer = ""
            # Why can't I pass the 'err' by itself?
            self.recvChannel.ch.send_exception(stdsocket.error, err)
Пример #2
0
class dispatcher(asyncore.dispatcher):
    connectChannel = None
    acceptChannel = None
    recvChannel = None

    def __init__(self, sock):
        # This is worth doing.  I was passing in an invalid socket which was
        # an instance of dispatcher and it was causing tasklet death.
        if not isinstance(sock, stdsocket.socket):
            raise StandardError("Invalid socket passed to dispatcher")
        asyncore.dispatcher.__init__(self, sock)

        # if self.socket.type == SOCK_DGRAM:
        #    self.dgramRecvChannels = {}
        #    self.dgramReadBuffers = {}
        #else:
        self.recvChannel = Channel(micro_send=True)
        self.readBufferString = ''
        self.readBufferList = []

        self.sendBuffer = ''
        self.sendToBuffers = []

        self.maxreceivebuf = 65536

    def writable(self):
        if self.socket.type != SOCK_DGRAM and not self.connected:
            return True
        return len(self.sendBuffer) or len(self.sendToBuffers)

    def accept(self):
        if not self.acceptChannel:
            self.acceptChannel = Channel(micro_send=True)
        return self.acceptChannel.recv()

    def connect(self, address):
        asyncore.dispatcher.connect(self, address)
        # UDP sockets do not connect.

        if self.socket.type != SOCK_DGRAM and not self.connected:
            if not self.connectChannel:
                # Prefer the sender.  Do not block when sending, given that
                # there is a tasklet known to be waiting, this will happen.
                self.connectChannel = Channel(prefer_sender=True)
            self.connectChannel.recv()

    def send(self, data):
        self.sendBuffer += data
        micro_block()
        return len(data)

    def sendall(self, data):
        # WARNING: this will busy wait until all data is sent
        # It should be possible to do away with the busy wait with
        # the use of a channel.
        self.sendBuffer += data
        while self.sendBuffer:
            micro_block()
        return len(data)

    def sendto(self, sendData, sendAddress):
        waitChannel = None
        for idx, (data, address, channel,
                  sentBytes) in enumerate(self.sendToBuffers):
            if address == sendAddress:
                self.sendToBuffers[idx] = (data + sendData, address, channel,
                                           sentBytes)
                waitChannel = channel
                break
        if waitChannel is None:
            waitChannel = Channel(micro_send=True)
            self.sendToBuffers.append((sendData, sendAddress, waitChannel, 0))
        return waitChannel.recv()

    # Read at most byteCount bytes.
    def recv(self, byteCount):
        self.maxreceivebuf = byteCount
        if len(self.readBufferString) < byteCount:
            # If our buffer is empty, we must block for more data we also
            # aggressively request more if it's available.
            if len(self.readBufferString
                   ) == 0 or self.recvChannel.ch.balance > 0:
                self.readBufferString += self.recvChannel.recv()
        # Disabling this because I believe it is the onus of the application
        # to be aware of the need to run the scheduler to give other tasklets
        # leeway to run.
        # stackless.schedule()
        ret = self.readBufferString[:byteCount]
        self.readBufferString = self.readBufferString[byteCount:]
        return ret

    def recvfrom(self, byteCount):
        ret = ""
        address = None
        self.maxreceivebuf = byteCount
        return self.recvChannel.recv()

    def close(self):
        asyncore.dispatcher.close(self)
        self.connected = False
        self.accepting = False
        self.sendBuffer = ''  # breaks the loop in sendall

        # Clear out all the channels with relevant errors.

        if self.acceptChannel is not None:
            while self.acceptChannel and self.acceptChannel.ch.balance < 0:
                self.acceptChannel.send_exception(error, 9,
                                                  'Bad file descriptor')
        if self.connectChannel is not None:
            while self.connectChannel and self.connectChannel.ch.balance < 0:
                self.connectChannel.send_exception(error, 10061,
                                                   'Connection refused')
        if self.recvChannel is not None:
            while self.recvChannel and self.recvChannel.ch.balance < 0:
                # The closing of a socket is indicted by receiving nothing.  The
                # exception would have been sent if the server was killed, rather
                # than closed down gracefully.
                self.recvChannel.ch.send("")
                #self.recvChannel.send_exception(error, 10054, 'Connection reset by peer')

    # asyncore doesn't support this.  Why not?
    def fileno(self):
        # XXX: self.socket.fileno() raises a Bad file descriptor error.
        #      Therefore, we're using _fileno as a hack. This has to be
        #      cleaned.
        # return self.socket.fileno()
        return self._fileno

    def handle_accept(self):
        if self.acceptChannel and self.acceptChannel.ch.balance < 0:
            currentSocket, clientAddress = asyncore.dispatcher.accept(self)
            currentSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
            # Give them the asyncore based socket, not the standard one.
            currentSocket = self.wrap_accept_socket(currentSocket)
            self.acceptChannel.send((currentSocket, clientAddress))

    # Inform the blocked connect call that the connection has been made.
    def handle_connect(self):
        if self.socket.type != SOCK_DGRAM and self.connectChannel is not None:
            self.connectChannel.send(None)

    # Asyncore says its done but self.readBuffer may be non-empty
    # so can't close yet.  Do nothing and let 'recv' trigger the close.
    def handle_close(self):
        pass

    # Some error, just close the channel and let that raise errors to
    # blocked calls.
    def handle_expt(self):
        self.close()

    def handle_read(self):
        try:
            if self.socket.type == SOCK_DGRAM:
                ret, address = self.socket.recvfrom(self.maxreceivebuf)
                self.recvChannel.send((ret, address))
            else:
                ret = asyncore.dispatcher.recv(self, self.maxreceivebuf)
                # Not sure this is correct, but it seems to give the
                # right behaviour.  Namely removing the socket from
                # asyncore.
                if not ret:
                    self.close()
                self.recvChannel.send(ret)
        except stdsocket.error, err:
            # XXX Is this correct?
            # If there's a read error assume the connection is
            # broken and drop any pending output
            if self.sendBuffer:
                self.sendBuffer = ""
            # Why can't I pass the 'err' by itself?
            self.recvChannel.ch.send_exception(stdsocket.error, err)