@synchronized('_frame_read_lock')
    def read_frame(self):
        """Read frame from connection

        Note that the frame may be destined for any channel. It is permitted to interleave frames
        from different channels.

        :return: frame
        :rtype: amqpy.proto.Frame
        """
        frame = Frame()
        try:
            # read frame header: 7 bytes
            frame_header = self.read(7, True)
            frame.data.extend(frame_header)

            # read frame payload
            payload = self.read(frame.payload_size)
            frame.data.extend(payload)

            # read frame terminator byte
            frame_terminator = self.read(1)
            frame.data.extend(frame_terminator)

            if six.PY2:
                #: :type: int
                i_last_byte = six.byte2int(frame_terminator)
            else:
                # this fixes the change in memoryview in Python 3.3 (accessing an element returns the
                #  correct type)
                #: :type: int
                i_last_byte = six.byte2int(bytes(frame_terminator))
        except (OSError, IOError, socket.error) as exc:
            # don't disconnect for ssl read time outs (Python 3.2):
            # http://bugs.python.org/issue10272
            if isinstance(exc, SSLError) and 'timed out' in str(exc):
                raise socket.timeout()
            if get_errno(exc) not in _UNAVAIL and not isinstance(exc, socket.timeout):
                self.connected = False
            raise

        if i_last_byte == FrameType.END:
            if frame.frame_type == FrameType.HEARTBEAT:
                self.last_heartbeat_received = datetime.datetime.now()
            return frame
        else:
            raise UnexpectedFrame('Received {} while expecting 0xce (FrameType.END)'.format(hex(i_last_byte)))
dataset/ETHPy150Open veegee/amqpy/amqpy/transport.py/Transport.read_frame/original