class FileSender extends AbstractTransmission {
    /** Corresponding file channel to work with a given file. */
    @GridToStringExclude
    private FileIO fileIo;

    /**
     * @param file File which is going to be sent by chunks.
     * @param off File offset.
     * @param cnt Number of bytes to transfer.
     * @param params Additional file params.
     * @param plc Policy of handling data on remote.
     * @param stopChecker Node stop or process interrupt checker.
     * @param log Ignite logger.
     * @param factory Factory to produce IO interface on given file.
     * @param chunkSize Size of chunks.
     * @throws IOException If fails.
     */
    public FileSender(
        File file,
        long off,
        long cnt,
        Map<String, Serializable> params,
        TransmissionPolicy plc,
        BooleanSupplier stopChecker,
        IgniteLogger log,
        FileIOFactory factory,
        int chunkSize
    ) throws IOException {
        super(new TransmissionMeta(file.getName(), off, cnt, params, plc, null), stopChecker, log, chunkSize);

        assert file != null;

        fileIo = factory.create(file);
    }

    /**
     * @param ch Output channel to write file to.
     * @param oo Channel to write meta info to.
     * @param rcvMeta Connection meta received.
     * @throws IOException If a transport exception occurred.
     * @throws InterruptedException If thread interrupted.
     */
    public void send(WritableByteChannel ch,
        ObjectOutput oo,
        @Nullable TransmissionMeta rcvMeta
    ) throws IOException, InterruptedException {
        updateSenderState(rcvMeta);

        // Write flag to remote to keep currnet transmission opened.
        oo.writeBoolean(false);

        // Send meta about current file to remote.
        oo.writeObject(new TransmissionMeta(meta.name(),
            meta.offset() + transferred,
            meta.count() - transferred,
            meta.params(),
            meta.policy(),
            null));

        while (hasNextChunk()) {
            if (Thread.currentThread().isInterrupted())
                throw new InterruptedException("Sender thread has been interruped");

            if (stopped())
                throw new IgniteException("Sender has been cancelled due to the local node is stopping");

            writeChunk(ch);
        }

        assert transferred == meta.count() : "File is not fully transferred [expect=" + meta.count() +
            ", actual=" + transferred + ']';
    }

    /**
     * @param rcvMeta Conneciton meta info.
     */
    private void updateSenderState(TransmissionMeta rcvMeta) {<FILL_FUNCTION_BODY>}

    /**
     * @param ch Channel to write data to.
     * @throws IOException If fails.
     */
    private void writeChunk(WritableByteChannel ch) throws IOException {
        long batchSize = Math.min(chunkSize, meta.count() - transferred);

        long sent = fileIo.transferTo(meta.offset() + transferred, batchSize, ch);

        if (sent > 0)
            transferred += sent;
    }

    /** {@inheritDoc} */
    @Override public void close() {
        U.closeQuiet(fileIo);
    }

    /** {@inheritDoc} */
    @Override public String toString() {
        return S.toString(FileSender.class, this, "super", super.toString());
    }
}

        // The remote node doesn't have a file meta info.
        if (rcvMeta == null || rcvMeta.offset() < 0) {
            transferred = 0;

            return;
        }

        long uploadedBytes = rcvMeta.offset() - meta.offset();

        assertParameter(meta.name().equals(rcvMeta.name()), "Attempt to transfer different file " +
            "while previous is not completed [meta=" + meta + ", meta=" + rcvMeta + ']');

        assertParameter(uploadedBytes >= 0, "Incorrect sync meta [offset=" + rcvMeta.offset() +
            ", meta=" + meta + ']');

        // No need to set new file position, if it is not changed.
        if (uploadedBytes == 0)
            return;

        transferred = uploadedBytes;

        U.log(log, "The number of transferred bytes after reconnect has been updated: " + uploadedBytes);
    
<methods>public org.apache.ignite.internal.managers.communication.TransmissionMeta state() ,public java.lang.String toString() ,public long transferred() <variables>protected final non-sealed int chunkSize,protected final non-sealed org.apache.ignite.IgniteLogger log,protected org.apache.ignite.internal.managers.communication.TransmissionMeta meta,private final non-sealed java.util.function.BooleanSupplier stopChecker,protected long transferred