Skip to content
Advertisement

How to upload a file to server with Tkinter filedialog

I have a client that let user to browse a file and upload to a server. Currently I’m just using command terminal to operate the program. When user types in fup in the terminal, the program will ask for filename and the file will be uploaded to the server if the filename input by user is valid.

So, what I want now is letting user to browse any file directory from a GUI without typing the filename to upload. I’ve tried to implement filedialog but it seems like not working. When I browse and upload a file, the server does not receive any new file. I am stuck with issues almost a week already but still couldn’t find any solution. Hope someone could help me. Thanks in advance.

Client.py

import socket, sys, os
from tkinter import filedialog
from tkinter import *

import time, shutil
root = Tk()
# socket creating
def sock():
    try:
        s = socket.socket()
        host = input('Enter Target IP :')
        port = 9999
        s.connect((host, port))
        return (host, s)
    except:
        print("Error: In binding")
        sock()


host, s = sock()

# upload file to client

def fup(conn):
    try:
        filename = filedialog.askopenfilename(parent=root, initialdir="/", title='Please select a directory')
        if os.path.isfile(filename):
            conn.send(str("fup~" + filename).encode("utf-8"))
            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)
                        sys.stdout.write("r|" + "█" * int((totalSend / float(filesize)) * 50) + "|{0:.2f}".format(
                            (totalSend / float(filesize)) * 100) + "%  ")
                        sys.stdout.flush()
                    print("nUpload Completed!")
        else:
            print("File Does Not Exist!")
    except:
        print("Error")


# download file from client
def fdown(conn):
    try:
        print(os.getcwd())
        filename = input("nMANO >>Filename? -> ")
        if filename != 'q':
            conn.send(("fdown~" + filename).encode("utf-8"))
            data = conn.recv(1024).decode("utf-8")
            if data[:6] == 'EXISTS':
                filesize = data[6:]
                msg = input("File exists, " + str(filesize) + "Bytes, download? (Y/N)? -> ").upper()
                if msg == 'Y':
                    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)
                        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()
            else:
                print("File Does Not Exist!")
    except:
        print("Error")


# commands that perform on client
def mano(cip, conn):
    fup(conn)


def run():
    mano(host, s)

upload_button = Button(root, text="upload", command=run)
upload_button.place(x=130, y=17, width=50, height=22)

root.mainloop()

Server.py

import socket, os, subprocess, shutil, pickle, struct, threading
## gettig the hostname by socket.gethostname() method
hostname = socket.gethostname()
## getting the IP address using socket.gethostbyname() method
ip_address = socket.gethostbyname(hostname)

# 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)
        ## printing the hostname and ip_address
        print(f"Hostname: {hostname}")
        print(f"IP Address: {ip_address}")
        print(f"Running Port: {port}")
    except socket.error as msg:
        bind_socket()
        print(bind_socket())


# send file list
def flist(conn):
    try:
        arr = pickle.dumps(os.listdir())
        conn.send(arr)
        print(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)
        else:
            s.send(".".encode('utf-8'))


def socket_accept():
    while True:
        conn, address = s.accept()
        t = threading.Thread(target=main, args=(conn,))
        t.start()


create_socket()
bind_socket()
socket_accept()

**After I click on upload and it show uploaded compelte, but the server doesn’t receive any new file. enter image description here

Advertisement

Answer

Since you have used filedialog.askopenfilename() to get the filename which is a full pathname, like for example C:/Users/heng/PycharmProjects/testtest/New System/test.txt. So the server gets the same full pathname and try to create the output file. But it will fail if C:/Users/heng/PycharmProjects/testtest/New System/ does not exists in server side.

To fix the issue, either sending the filename part (without the directory information) in client side:

def fup(conn):
    try:
        filename = filedialog.askopenfilename(parent=root, initialdir="/", title='Please select a directory')
        if os.path.isfile(filename):
            _, basename = os.path.split(filename)
            conn.send(str("fup~" + basename).encode("utf-8")) # use basename instead of filename
            ...

or remove the directory information in server side:

def fdown(fullname, conn): # renamed filename to fullname
    _, filename = os.path.split(fullname) # get the filename part only
    try:
        ...
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement