send file using socket python - python

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()

Related

Python socket doesn't send message

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.

Python socket file transfer not working only with pdf files

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

How to send a file back from server to client?

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?

Socket python Chat & File transfer

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!

Write a basic HTTP Server using socket API

I have this following code which is in my server.py file. It is waiting to receive data from the client. Additionally I cannot use any of the http libraries. Only the socket Library:
def handle_client(conn, addr):
print ('New client from', addr)
x = []
try:
while True:
data = conn.recv(1024)
decoded_data = data.decode('utf-8')
# if "GET / " in data.decode('utf-8'):
# handle_client_get(conn)
# else:
if data:
print(data)
x.append(decoded_data)
else:
print(x)
break
finally:
print("in close now")
conn.close()
The problem I am having is that I can only reach the print(x) statement once I manually CTRL + Cclose the client. Otherwise it doesn't print.
Why is that the case.
ANSWER
You need to send an acknowledgment to the client such that the data sent has been received correctly.
that will terminate the connection and not wait for a timeout.
This is because the client sends: Expect: 100-continue
And you need to send an acknowledgment back to the client
You need to implement the protocol which will have a means to tell you how much data there is to read. In the case of HTTP, the request starts with a CRLF delimited header, and we can read that to get the information we want.
w3.org has a good description of the http request protocol. Its more complicated than I want to implement here but I've included an example that pulls in the request header by reading the socket one character at a time and looking for an empty \n terminated line. By reading one character at a time, I don't have to implement my own line buffer.
The first line is the request method and the remaining lines are other parameters included with the request. For a POST, for instance, there would be more data still to read from the socket.
import re
def handle_client(conn, addr):
print ('New client from', addr)
header = []
line = []
try:
# read ascii http client header.
while True:
c = conn.recv(1)
# check for early termination
if not c:
return None
# check for end of request line
elif c == b"\n":
# make line a string to add to header
line = ''.join(line).decode('ascii').strip()
# are we at the empty line signalling end-of-header?
if not line:
break
header.append(line)
line = []
# filter out \r
elif c == b"\r":
continue
# request is first line of header
request_line = header.pop(0)
method, uri, http_version = re.split(r" +" request_line)
if method.upper() == "GET":
# this function needs more parameters... the uri to get and the protocol
# version to use.
handle_client_get(...)
finally:
print("in close now")
conn.close()
Edit:
Now that you mention this is a HTTP server and is to be done using only socket library, I suggest you remove certain complex elements from the program at this stage like removing the while block until this problem is solved.
server.py
def handle_client(conn, addr):
print ('New client from', addr)
x = []
try:
data = conn.recv(1024)
decoded_data = data.decode('utf-8')
if data:
print(data)
x.append(decoded_data)
else:
print(x)
break
finally:
print("in close now")
conn.close()
Original Answer:
Try sending an additional \n at the sender end and use the flush function later to send out any remaining data on the buffer something like:
sender.py
def send_data(data,sock_obj,addr):
sock_obj.send(data+"\n")
sock_obj.flush()

Categories