public byte[] scan(final InputStream is) throws IOException {
        try (Socket s = getSocket(); OutputStream outs = new BufferedOutputStream(s.getOutputStream())) {
            // handshake
            outs.write(asBytes("zINSTREAM\0"));
            outs.flush();
            final byte[] chunk = new byte[this.bufferSize];

            // send data
            int readLen = is.read(chunk);
            while (readLen >= 0) {
                // The format of the chunk is: '<length><data>' where <length> is
                // the size of the following data in bytes expressed as a 4 byte
                // unsigned
                // integer in network byte order and <data> is the actual chunk.
                // Streaming is terminated by sending a zero-length chunk.
                final byte[] length = ByteBuffer.allocate(4).putInt(readLen).array();
                outs.write(length);
                outs.write(chunk, 0, readLen);
                readLen = is.read(chunk);
            }

            // terminate scan
            outs.write(new byte[] {0, 0, 0, 0});
            outs.flush();

            // read reply
            try (InputStream clamIs = s.getInputStream()) {
                return readAll(clamIs);
            }
        }
    }
Streams the given data to the server in chunks. The whole data is not kept in memory. This method is preferred if you don't want to keep the data in
memory, for instance by scanning a file on disk. Since the parameter InputStream is not reset, you can not use the stream afterwards, as it will be left
in a EOF-state. If your goal is to scan some data, and then pass that data further, consider using {@link #scan(byte[]) scan(byte[] in)}.
<p>
Opens a socket and reads the reply. Parameter input stream is NOT closed.

@param is data to scan. Not closed by this method!
@return server reply
@throws IOException if there is an I/O problem
primefaces/src/main/java/org/primefaces/virusscan/impl/ClamDaemonClient.java