Search code examples
pythonsocketsjpegrecv

Prune file size sent from server socket


I am connecting to a pre-configured server that serves four different file formats with different sizes. Each file is appended with the file size...

Example: lighthouse.jpg

561276ÿØÿà JFIF  ` `  ÿî Adobe

The "561276" is the file size and needs to be pruned before saving the file.

Example: randomText.txt

45711111111111111111111111111111111111111111111111111111111
222222222222222222222222222222222222222222222222222222222
33333333333333333333333333333333333333333333333333
44444444444444444444444444444444444444444444444444444444
66666666666666666666
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cvccccccccccccccccccccccccccccccccccccccccccccccc
ddddddddddddddddddddddddddddddddddddddddddddddddddd

The "457" is the file size and needs to be pruned before saving the file.

Some files have a size that is only 3-digits long. Some have a file size that is 6-digits long (as seen here). I want to make my code size-agnostic; regardless of how many digits is in the size.

I've tried using:

    while len(buf) < 4:
        buf += sock.recv(4 - len(buf))
    size = struct.unpack('!i', buf)

but this only prunes the first four digits.

AND

I've tried using

len = sock.recv(4)
data = sock.recv(len)

but once again... only prunes the first four digits

Here is what I have so far:

def get_size():
    buf = ''
    while len(buf) < 4:
        buf += sock.recv(4 - len(buf))
    size = struct.unpack('!i', buf)
    print "[*] Receiving %s bytes" % size


def download_pic():

    size = get_size()
    fname = 'tst.jpg'

    with open(fname, 'wb') as img:
        while True:
            data = sock.recv(1024)
            if not data:
                break
            img.write(data)
    print '[*] {0} received!'.format(fname)


def main():
    doconnectionstuffandprinttoconsole() #establishes connection

    answer = input("[>] Your Selection: ")
    sock.send(str(answer))

    if answer == 2:
        download_pic()

    sock.close()

Any help in pruning the size from the file(s) would be greatly appreciated!


Solution

  • Jason Harper's suggestion (@jasonharper) got me thinking. When I ran repr(data) on the chunks from randomText.txt, I saw that it had a break in it that looked like...

    '457''1111111111111111111111...
    

    The server was attempting to send two different chunks (one at at time) but it kept getting merged into one chunk. So, I increased my sock.recv(64) up to sock.recv(256). And for some reason, it send two chunks!

    '457'
    '111111111...' [truncated]
    

    NEW AND IMPROVED CODE!

    import socket
    import sys
    import struct
    import os
    
    user1 = {'user1': 91827364}
    user2 = {'user2': 19283746}
    user3 = {'user3': 46372819}
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    sock.connect(('127.0.0.1', 2058))
    
    
    def print_data():
        data_rcv = sock.recv(1024)
        print "[-] {0}".format(data_rcv)
    
    
    def download_file(format):
        fname = 'download'
        fullname = fname + '.' + format
    
        try:
            with open(fullname, 'wb') as txt:
                len = sock.recv(256)
                while True:
                    data = sock.recv(int(len))
                    if not data:
                        break
                    txt.write(data)
            print("[*] {0} successfully downloaded with a length of {1} characters!".format(fullname, len))
        except Exception:
            print("[!] Error receiving file.  Please try again.")
    
    
    def connect():
        print("[*] Sending Length")
        sock.send("5")
    
        my_struct = struct.pack('5s i', 'user1', 91827364)
        print("[*] Sending User1 Struct")
        sock.send(my_struct)
    
        print_data()
    
    
    def main():
        print_data()
        connect()
    
        print_data()
    
        answer = input("[>] Your Selection: ")
        sock.send(str(answer))
    
        if answer == 2:         # Option to download Lighthouse.jpg
            download_file("jpg")
        elif answer == 4:       # Option to download randomText.txt
            download_file("txt")
    
        sock.close()
    
    
    if __name__ == "__main__":
        main()
    

    MY OUTPUT

    [-] Please enter credentials
    [*] Sending Length
    [*] Sending User1 Struct
    [-] Authenticated
    [-] Choose a file to retrieve from the following list (enter the number):
     1. photo.png
     2. Lighthouse.jpg
     3. npp.6.8.5.Installer.exe
     4. randomText.txt
    [>] Your Selection: 2
    [*] download.jpg successfully downloaded with a length of 561276 characters!