Data Compression and Archiving-zlib:GNU zlib Compression-Compression of Network Data

Keywords: socket zlib network

8.1.5 Compressed network data
The server in the next code list responds to a file name request with a stream compressor that writes a compressed version of the file to a socket that communicates with the client.

import zlib
import logging
import socketserver
import binascii

BLOCK_SIZE = 64

class ZlibRequestHandler(socketserver.BaseRequestHandler):
    logger = logging.getLogger('Server')

    def handle(self):
        compressor = zlib.compressobj(1)

        # Find out which file the client wants.
        filename = self.request.recv(1024).decode('utf-8')
        self.logger.debug('client asked for: %r',filename)

        # Send chunks of the file as they are compressed.
        with open(filename,'rb') as input:
            while True:
                block = input.read(BLOCK_SIZE)
                if not block:
                    break
                self.logger.debug('RAW %r',block)
                compressed = compressor.compress(block)
                if compressed:
                    self.logger.debug(
                        'SENDING %r',
                        binascii.hexlify(compressed))
                    self.request.send(compressed)
                else:
                    self.logger.debug('BUFFERING')

        # Send any data being buffered by the compressor.
        remaining = compressor.flush()
        while remaining:
            to_send = remaining[:BLOCK_SIZE]
            remaining = remaining[BLOCK_SIZE:]
            self.logger.debug('FLUSHING %r',
                              binascii.hexlify(to_send))
            self.request.send(to_send)
        return

if __name__ == '__main__':
    import socket
    import threading
    from io import BytesIO

    logging.basicConfig(
        level=logging.DEBUG,
        format='%(name)s: %(message)s',
        )
    logger = logging.getLogger('Client')

    # Set up a servre,running in a separate thread.
    address = ('localhost',0)  # Let the kernel assign a port.
    server = socketserver.TCPServer(address,ZlibRequestHandler)
    ip,port = server.server_address  # What port was assigned?

    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True)
    t.start()

    # Connect to the server as a client.
    logger.info('Contacting server on %s:%s',ip,port)
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,port))

    # Ask for a file.
    requested_file = 'lorem.txt'
    logger.debug('sending filename:%r',requested_file)
    len_sent = s.send(requested_file.encode('utf-8'))

    # Receive a response.
    buffer = BytesIO()
    decompressor = zlib.decompressobj()
    while True:
        response = s.recv(BLOCK_SIZE)
        if not response:
            break
        logger.debug('READ %r',binascii.hexlify(response))
    # Include any uncomsumed data when
    # feeding the decompressor.
    to_decompress = decompressor.unconsumed_tail + response
    while to_decompress:
        decompressed = decompressor.decompress(to_decompress)
        if decompressed:
            logger.debug('DECOMPRESSED %r',decompressed)
            buffer.write(decompressed)
            # Look for unconsumed data due to buffer overflow.
            to_decompress = decompressor.unconsumed_tail
        else:
            logger.debug('BUFFERING')
            to_decompress = None

# Deal with reamining inside the decompressor buffer.
remainder = decompressor.flush()
if remainder:
    logger.debug('FLUSHED %r',remainder)
    buffer.write(remainder)

full_response = buffer.getvalue()
lorem = open('lorem.txt','rb').read()
logger.debug('response matches file contents: %s',
             full_response == lorem)

# Clean up.
s.close()
server.socket.close()

We think we've divided this code list to show buffering behavior, where data is passed to compress() or decompress(), but no fully compressed or uncompressed output block is available.The client connects to the socket and requests a file.It then loops to accept the compressed data block.Since a block may not contain enough information to fully decompress, previously received reputation data will be combined with the new data and passed to the decompressor.When data is decompressed, it is appended to a buffer, and the contents of the file are compared at the end of the processing cycle.

Warning: The head of this server village has an obvious security risk.Do not run this program in an open Internet or environment where security issues may have a serious impact.
Run result:


Posted by coder9 on Tue, 03 Dec 2019 12:02:54 -0800