コード例 #1
0
class SocketTransport(object):
    """Provides network I/O for a Proton Transport via a socket.
    """

    def __init__(self, socket, name=None):
        """socket - Python socket. Expected to be configured and connected.
        name - optional name for this SocketTransport
        """
        self._name = name
        self._socket = socket
        self._transport = Transport()
        self._read_done = False
        self._write_done = False
        self._next_tick = 0

    def fileno(self):
        """Allows use of a SocketTransport by the select module.
        """
        return self._socket.fileno()

    @property
    def transport(self):
        return self._transport

    @property
    def socket(self):
        return self._socket

    @property
    def name(self):
        return self._name

    def tick(self, now):
        """Invoke the transport's tick method.  'now' is seconds since Epoch.
        Returns the timestamp for the next tick, or zero if no next tick.
        """
        self._next_tick = self._transport.tick(now)
        return self._next_tick

    @property
    def next_tick(self):
        """Timestamp for next call to tick()
        """
        return self._next_tick

    @property
    def need_read(self):
        """True when the Transport requires data from the network layer.
        """
        return (not self._read_done) and self._transport.capacity() > 0

    @property
    def need_write(self):
        """True when the Transport has data to write to the network layer.
        """
        return (not self._write_done) and self._transport.pending() > 0

    def read_input(self):
        """Read from the network layer and processes all data read.  Can
        support both blocking and non-blocking sockets.
        """
        if self._read_done:
            return None

        c = self._transport.capacity()
        if c < 0:
            try:
                self._socket.shutdown(socket.SHUT_RD)
            except:
                pass
            self._read_done = True
            return None

        if c > 0:
            try:
                buf = self._socket.recv(c)
                if buf:
                    self._transport.push(buf)
                    return len(buf)
                # else socket closed
                self._transport.close_tail()
                self._read_done = True
                return None
            except socket.timeout, e:
                raise  # let the caller handle this
            except socket.error, e:
                err = e.args[0]
                if err != errno.EAGAIN and err != errno.EWOULDBLOCK and err != errno.EINTR:
                    # otherwise, unrecoverable:
                    self._transport.close_tail()
                    self._read_done = True
                raise
            except:  # beats me...