@Override
    public Result next() throws IOException {
      if (cache.size() == 0) {
        setupNextScanner();
        try {
          List<TResult> tResults =
            client.getScannerResults(tableNameInBytes, scan, scan.getCaching());
          Result[] results = ThriftUtilities.resultsFromThrift(tResults);
          boolean firstKey = true;
          for (Result result : results) {
            // If it is a reverse scan, we use the last result's key as the startkey, since there is
            // no way to construct a closet rowkey smaller than the last result
            // So when the results return, we must rule out the first result, since it has already
            // returned to user.
            if (firstKey) {
              firstKey = false;
              if (scan.isReversed() && lastResult != null) {
                if (Bytes.equals(lastResult.getRow(), result.getRow())) {
                  continue;
                }
              }
            }
            cache.add(result);
            lastResult = result;
          }
        } catch (TException e) {
          throw new IOException(e);
        }
      }

      if (cache.size() > 0) {
        return cache.poll();
      } else {
        // scan finished
        return null;
      }
    }
A scanner to perform scan from thrift server getScannerResults is used in this scanner
hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftTable.java