Johnnyyy
Johnnyyy

Reputation: 103

Socket can't read large files. Python

Im doing a project where it connect to a server directory and read all their files. So i just wrote a code to download the server files whenever i click on it. I can read small size file with no issues, but when i want to view a large content, only 1 line can be view and store to a list. Although i cant read all the large content, but im able to download it with no issues.

I can read and download all small size content with no issues: enter image description here

The large file that i want to read from: enter image description here

Output that i got when i read the large files. (Cant read all the content but i successfully to download the full content file) enter image description here

CLIENT CODE:

def mouseHover(event):
           x = lbox.curselection()[0]
           file = lbox.get(x)
           ext = (".txt", ".csv")
           if file.endswith(ext):
               self.s.send(("fdown~" + file).encode("utf-8")) #must have
               data = self.s.recv(1024).decode("utf-8")
               if data[:6] == 'EXISTS':
                   filesize = data[6:]
                   self.s.send("OK".encode("utf-8"))
                   f = open(file, 'wb')  # must have
                   data = (self.s.recv(1024))
                   totalRecv = len(data)
                   f.write(data)
                   while int(totalRecv) < int(filesize):
                       data = self.s.recv(1024)
                       totalRecv += len(data)
                       f.write(data)
                       sys.stdout.write("\r|" + "█" * int((totalRecv / float(filesize)) * 50) + "|{0:.2f}".format(
                           (totalRecv / float(filesize)) * 100) + "%  ")
                       sys.stdout.flush()
                       time.sleep(0.01)
                   print("\nDownload Complete!")
                   f.close()

                   global data2
                   data2= data.splitlines()
                   print(data2)
                   self.text.delete('1.0', tk.END)
                   self.text.insert(tk.END, data)
           else:
               messagebox.showinfo("WARNING", "Currently only .txt/csv file is supported.")


       lbox.bind("<<ListboxSelect>>", mouseHover)

SERVER CODE:


# Create a Socket ( connect two computers)
def create_socket():
    try:
        global host
        global port
        global s
        host = ""
        port = 9999
        s = socket.socket()
    except socket.error as msg:
        create_socket()


# Binding the socket and listening for connections
def bind_socket():
    try:
        global host
        global port
        global s
        s.bind((host, port))
        s.listen(5)
    except socket.error as msg:
        bind_socket()




# send file list

def flist(conn):
    try:
        arr = pickle.dumps(os.listdir())
        conn.send(arr)
    except:
        conn.send(('Error').encode("utf-8"))



# accept file from server

def fdown(filename, conn):
    try:
        data = conn.recv(1024).decode("utf-8")
        if data[:6] == 'EXISTS':
            filesize = data[6:]
            conn.send("OK".encode("utf-8"))
            f = open(filename, 'wb')
            data = (conn.recv(1024))
            totalRecv = len(data)
            f.write(data)
            while int(totalRecv) < int(filesize):
                data = conn.recv(1024)
                totalRecv += len(data)
                f.write(data)
            f.close()
    except:
        conn.send(('Error').encode("utf-8"))


# send file
def fup(filename, conn):
    if os.path.isfile(filename):
        conn.send(str.encode("EXISTS " + str(os.path.getsize(filename))))
        filesize = int(os.path.getsize(filename))
        userResponse = conn.recv(1024).decode("utf-8")
        if userResponse[:2] == 'OK':
            with open(filename, 'rb') as f:
                bytesToSend = f.read(1024)
                conn.send(bytesToSend)
                totalSend = len(bytesToSend)
                while int(totalSend) < int(filesize):
                    bytesToSend = f.read(1024)
                    totalSend += len(bytesToSend)
                    conn.send(bytesToSend)
    else:
        conn.send("ERROR".encode("utf-8"))




# main
def main(s):
    while True:
        data = (s.recv(1024)).decode("utf-8").split('~')

        if data[0] == 'fdown':
            fup(data[1], s)
        elif data[0] == 'fup':
            fdown(data[1], s)
        elif data[0] == 'flist':
            flist(s)

            break
        else:
            s.send(".".encode('utf-8'))


# Establish connection with a client (socket must be listening)

def socket_accept():
    conn, address = s.accept()
    main(conn)
    conn.close()


create_socket()
bind_socket()
socket_accept()

Upvotes: 0

Views: 260

Answers (1)

Barmar
Barmar

Reputation: 781098

After you read each block of data, concatenate it to a string containing the whole file. Then at the end of the loop you can split this into lines and display it in the text box.

There's also no need to limit your recv() calls to 1000 bytes. Use filesize - totalRecv as the limit, and it will receive as much as is available, but not go past the end of the file.

There's no need to convert filesize to int every time through the loop, do it once when you assign the variable.

def mouseHover(event):
    x = lbox.curselection()[0]
    file = lbox.get(x)
    ext = (".txt", ".csv")
    if file.endswith(ext):
        self.s.send(("fdown~" + file).encode("utf-8")) #must have
        data = self.s.recv(1024).decode("utf-8")
        if data[:6] == 'EXISTS':
            filesize = int(data[6:])
            self.s.send("OK".encode("utf-8"))
            all_data = ''
            with open(file, 'wb') as f: # must have
                totalRecv = 0
                while totalRecv < filesize:
                    data = self.s.recv(filesize - totalRecv)
                    totalRecv += len(data)
                    all_data += data
                    f.write(data)
                    sys.stdout.write("\r|" + "█" * int((totalRecv / filesize) * 50) + "|{0:.2f}".format(
                            (totalRecv / filesize) * 100) + "%  ")
                    sys.stdout.flush()
                    time.sleep(0.01)
                print("\nDownload Complete!")

            global data2
            data2= all_data.splitlines()
            print(data2)
            self.text.delete('1.0', tk.END)
            self.text.insert(tk.END, all_data)
    else:
        messagebox.showinfo("WARNING", "Currently only .txt/csv file is supported.")

lbox.bind("<<ListboxSelect>>", mouseHover)

Upvotes: 1

Related Questions