I'm writing a file transfer server and client that transfers csv and pdf files, and checks a hash for integrity, and saves it to a local directory. Everything works fine on the csv, but when I try to send a pdf from client to server, the file will not be written and the server just saves the title in a 0kB pdf file. Not sure what to do from here, recv(bytes_read) keeps coming up empty.
Client send file function (Ignore the gross indentation, this is first stack overflow post)
def putFile(filename, serverIP, port, BUFFER_SIZE,s): #sends file to a server
filesize= os.path.getsize(filename)
#make and send hash
hexhash=getHash(filename)#make hash
s.send(hexhash.encode())#send hash
print("Hash sent",hexhash)
received=s.recv(BUFFER_SIZE).decode()#receive response from server
print(received)#print response
#send file
s.send(f"{filename}[SEPARATOR]{filesize}".encode())#send file name and size
with open(filename, "rb") as f: #open as read in binary to read in chunks
while True:
bytes_read = f.read(BUFFER_SIZE)#.encode() # read the bytes from the file in 4096B
if not bytes_read: # file transmitting is done
print("Sent")
#s.sendall(bytes_read)
#s.send(("").encode())
break
s.sendall(bytes_read) #sendall assures transimission in busy networks
print(bytes_read)
print("waiting")
received=s.recv(BUFFER_SIZE).decode()#receive response from server about hash
print(received)#print response
if received== "Good hash":
print("File stored")
elif received=="Bad Hash":
print("File sent does not match file received")
s.close()
return
#END SEND FILE
server function
storeFile(fileheader, cli, hexhash): #eceives a file from a client
filename, filedata=fileheader.split("[SEPARATOR]")
filename=os.path.basename(filename)#just the file name
print("File:",filename)
#filesize=int(filesize)
cli.setblocking(False)
with open(filename, "wb") as f: #save file
while True:
print("loop")
try:
print("trying")
bytes_read = cli.recv(BUFFER_SIZE)# read up to BUFFSIZE bytes from the client
print("reading:",bytes_read)
except socket.error as e:
print("except")
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print("File Saved")
break
else:
# a "real" error occurred
print(e)
sys.exit(1)
else:
# got a message, do something :)
print("write")
f.write(bytes_read) # write to the file the bytes we just received)
#cli.close()
cli.setblocking(True)
#receive hash
check=checkHash(hexhash,filename)#check the hash given and the file hash, hash and file are given
if check: #hashes match
cli.send(("Good hash").encode())#respond to clent that hashes match
#print(received.split(SEPARATOR))
#s.close()
#END FILE RECEIPT"""
elif not check:
cli.send("Bad hash".encode())
#cli.close()
return
Related
I'm trying to create a python application that allows you to transfer files from the client to a server. The operation consists in sending a string to the server to indicate that we are sending a file and then the client sends the file name, its length and finally the contents of the file to the server. finally, the server confirms that the file has been saved and sends the confirmation message to the client
client.py
c.send(f"FILES:{files};{folder[index:]}".encode(FORMAT))
msg = c.recv(SIZE).decode(FORMAT)
print(f"[SERVER]: {msg}")
for i in range(len(files)):
c.send(files[i].encode(FORMAT))
print(f"[SERVER]: {c.recv(SIZE).decode(FORMAT)}") # send fileName
length = os.path.getsize(folder + "\\" + files[i])
c.send(str(length).encode(FORMAT))
print(f"[SERVER]: {c.recv(SIZE).decode(FORMAT)}") # send size
file = open(folder + "\\" + files[i], 'rb')
print(f"File read: {file.read()}")
try:
c.send(file.read()) #send bytes of file
except Exception as e:
print(f"[ERROR]: {e}")
print(f"[SERVER]: {c.recv(SIZE).decode(FORMAT)}") # complete writing on server
server.py
elif cmd == "FILES":
try:
data, path = data.split(';')
conn.send("Received files".encode(FORMAT))
while True:
nameFile = conn.recv(SIZE).decode(FORMAT)
conn.send(f"Received FileName {nameFile}".encode(FORMAT)) # received fileName
file = open(basePath + "\\" + path + "\\" + nameFile, 'wb')
print(f"[SERVER]: Opened: {file}")
length = conn.recv(SIZE).decode(FORMAT)
print(f"[CLIENT]: Length of files: {length}")
conn.send("Received size".encode(FORMAT)) # received size
bytesSend = conn.recv(length)
print(f"[CLIENT] Received bytes: {conn.recv(length)}")
file.write(bytesSend)
file.close
conn.send(f"File {nameFile} receive and saved".encode(FORMAT)) #complete writing
except:
pass
But when I try to send everything works up to c.send(file.read()). practically the client sends (but in reality it does not) the contents of the file to the server and passes to the last c.recv where it waits for the server confirmation but the server does not receive any contents of the file. Consequently, the server waits for the contents of the file to arrive but the client times out as it waits for confirmation from the server.
I have to implement a client-server application in which the client has to send a text file with data. The server has to receive the file, correct the misspelled words, and then return the file to the client.
I can now successfully send a file from client to server and I am able to correct the spelling. Now, I am not sure how to send the file back from the server to the client.
Here is my current code:
Client:
def readFile(self):
global f
filename = filedialog.askopenfilename(filetypes = [('txt', '*txt')])
# filename = filedialog.askopenfilename(initialdir= "C://Users//Desktop//assignments//spellcheck-master")
fileHandle = open(filename, 'r')
for i, line in enumerate(fileHandle.readlines()):
# import pdb;pdb.set_trace()
message = (f"{self.name}: {line}")
client.send(message.encode(FORMAT))
fileHandle.close()
Server:
def handle(self, conn, addr):
# receive the file infos
# receive using client socket, not server socket
# import pdb; pdb.set_trace()
received = conn.recv(BUFFER_SIZE).decode(FORMAT)
filename, filesize = received.split(SEPARATOR)
# remove absolute path if there is
filename = "/Users/Desktop/Distributed_System/spellcheck/convertextTxt.txt"
# convert to integer
filesize = int(filesize)
# start receiving the file from the socket
# and writing to the file stream
f = open(filename, 'w')
while True:
# read 1024 bytes from the socket (receive)
bytes_read = conn.recv(BUFFER_SIZE)
if not bytes_read:
print("Nothing received")
# nothing is received
# file transmitting is done
break
# write to the file the bytes we just received
rtf = bytes_read.decode(FORMAT)
text = rtf_to_text(rtf)
convertedTxt = self.spellCheck(text)
f.write(convertedTxt)
f.close()
Now, how to send the converted file back from server to client?
I wrote a function to send a file using a socket. It sends first the size of the file and then sends blocks of 9999 bytes to the client until the file ends. the problem is when the server reads the file, the file ends too fast. for example, for a file with 180,000 bytes, it ends after 2 blocks. I couldn't understand why this happens and I tried to run the read on this file in the terminal and it worked fine but here it doesn't. As much as I know the problem is supposed to be in the sever because when I checked, the server doesn't send all the data he is supposed to send because after about 2 read() calls it returns an empty string even though most of the file haven't been read.
here is the server code:
MAX_LENGTH_OF_SEND = 9999
def send_file(path, client_socket):
"""send a file to the client. if succeeded return success, else return error massage
:param path: path of the file to send
:param client_socket: the socket of the client to send to
:return: if success return 'success sending a file' else, return error massage
"""
try:
size = os.stat(path).st_size
print(size)
# send the length of the file to the client
send(str(size), client_socket)
read = 0
with open(path, "rb") as file1:
massage = file1.read(MAX_LENGTH_OF_SEND)
read += MAX_LENGTH_OF_SEND
while read < size:
binary_send(massage, client_socket)
massage = file1.read(MAX_LENGTH_OF_SEND)
read += MAX_LENGTH_OF_SEND
print(f"The file {path} has been sent")
except Exception as e:
print(f"Couldn't send file because {e}")
return "Error: " + str(e)
return "success sending a file"
def send(msg, client_socket):
""" sending a massage to a client by sending the length of the massage first
:param msg: the massage to send
:param client_socket: the client to send the massage
"""
client_socket.send(str(len(msg)).encode())
client_socket.send(msg.encode())
def binary_send(msg, client_socket):
""" sending a massage to a client by sending the length of the massage first without encoding the massage
:param msg: the massage to send
:param client_socket: the client to send the massage
"""
print(f"len = {str(len(msg)).encode()}")
client_socket.send(str(len(msg)).encode())
client_socket.send(msg)
Here is the client code:
data = receive_msg(my_socket)
if data.startswith("Error:"):
print(data)
else:
if SENT_PICTURE_PATH.endswith("\\"):
path = SENT_PICTURE_PATH + request[1]
else:
path = SENT_PICTURE_PATH + "\\" + request[1]
if not os.path.exists(path):
os.makedirs(path)
with open(path, "wb") as file:
size = int(data)
given = 0
error = False
while not error and given < size:
length = int(my_socket.recv(4).decode())
print(length)
data = my_socket.recv(length)
print(data)
try:
if data.decode().startswith("Error:"):
error = True
print(data.decode())
except UnicodeDecodeError or ValueError:
pass
if not error:
file.write(data)
size += length
def receive_msg(my_socket):
"""receive a massage from the server with a length of 99 max
:param my_socket: the socket to get from
:return: the massage
"""
length = int(my_socket.recv(2).decode())
return my_socket.recv(length).decode()
I'm currently trying to implement a chatroom + file transfer application with python 3 and socket for a university task.
I'm using code from this GitHub repo https://github.com/an09mous/pyChat for the chatroom and wrote some code for the file transfer:
Client send method:
file = open(filename, "rb")
file_data = file.read(1024)
s.send(file_data)
file.close()
print("Data has been transmitted successfully")
Server receive method:
filename = 'ClientTransfer2.txt'
file = open(filename, 'wb')
file_data = conn.recv(1024)
file.write(file_data)
file.close()
print("File has been received successfully.")
I tried to merge both codes together by checking if the last message is "Send file", and if so sending a file from the client and receiving it on the server:
Server receive:
try:
msg = conn.recv(4096)
if msg:
if decodeMessage(msg) == "Send file":
receiveFile(conn)
print(type(msg))
msg = clientName + ": " + decodeMessage(msg)
print(msg)
broadcast(encodeMessage(msg), conn)
else:
removeClient(conn)
break
Client send:
while True:
try:
msg = input()
if msg == "Send file":
sendFile()
else:
msg = encodeMessage(msg)
server.send(msg)
except:
print("Failed to connect to server!")
break
Now I always get the content of my .txt file that I'm trying to send printed as a "chat message" instead of a file being written to the directory.
I understand that this is due to both chat messages and files being coded into bytes and sent. How can I differentiate between a file that is being sent and a text message?
Googleing that topic, I have not found an implementation of both chat + file transfer for Python, but if you know one, please let me know so I can try to understand their code and maybe get inspired by that solution ;)
Thanks in advance!
Sometimes, FTP server closes connection before file is completely downloaded..
Here is my code:
ftp = ftplib.FTP(site)
ftp.login(user, pw)
ftp.cwd(dir)
remotefiles = ftp.nlst()
for file in remotefiles:
if fnmatch.fnmatch(file, match_text):
if os.path.exists(file):
if True: print file, 'already fetched'
else:
if True: print 'Downloading', file
local = open(file, 'wb')
try:
ftp.retrbinary('RETR ' + file, local.write)
finally:
local.close()
if True: print 'Download done.'
You can specify a timeout parameter in the FTP constructor and set it to 0 or something very large value like sys.maxint.
class ftplib.FTP([host[, user[, passwd[, acct[, timeout]]]]])
Additionally, you can turn on debugging to see what's going on behind the scenes.
ftp = ftplib.FTP(site, user, pw, timeout=0)
ftp.set_debuglevel(2)
Hope this helps.