Need to transfer multiple files from client to server - python

I'm recently working on a project in which I'm basically making a dropbox clone. The server and client are working fine but I'm having a slight issue. I'm able to transfer a single file from the client to the server but when I try to transfer all the files together it gives me an error after the transfer of the first file so basically my code is only working for a single file. I need to make it work for multiple files. Any help will be appreciated. Here's my code
Server Code
import socket
import thread
import hashlib
serversock = socket.socket()
host = socket.gethostname();
port = 9000;
serversock.bind((host,port));
filename = ""
serversock.listen(10);
print "Waiting for a connection....."
clientsocket,addr = serversock.accept()
print("Got a connection from %s" % str(addr))
while True:
size = clientsocket.recv(1)
filesz = clientsocket.recv(1)
if filesz.isdigit():
size += filesz
filesize = int(size)
else:
filesize = int(size)
print filesize
for i in range(0,filesize):
if filesz.isdigit():
filename += clientsocket.recv(1)
else:
filename += filesz
filesz = "0"
print filename
file_to_write = open(filename, 'wb')
while True:
data = clientsocket.recv(1024)
#print data
if not data:
break
file_to_write.write(data)
file_to_write.close()
print 'File received successfully'
serversock.close()
Client Code
import socket
import os
import thread
s = socket.socket()
host = socket.gethostname()
port = 9000
s.connect((host, port))
path = "C:\Users\Fahad\Desktop"
directory = os.listdir(path)
for files in directory:
print files
filename = files
size = bytes(len(filename))
#print size
s.send(size)
s.send(filename)
file_to_send = open(filename, 'rb')
l = file_to_send.read()
s.sendall(l)
file_to_send.close()
print 'File Sent'
s.close()
Here's the error that I get
Waiting for a connection.....
Got a connection from ('192.168.0.100', 58339)
13
Betternet.lnk
File received successfully
Traceback (most recent call last):
File "server.py", line 22, in <module>
filesize = int(size)
ValueError: invalid literal for int() with base 10: ''

There are several minor issues in your snippet. Maybe you could do something like this?
import socket
import thread
import hashlib
serversock = socket.socket()
host = socket.gethostname();
port = 9000;
serversock.bind((host,port));
filename = ""
serversock.listen(10);
print "Waiting for a connection....."
clientsocket,addr = serversock.accept()
print("Got a connection from %s" % str(addr))
while True:
size = clientsocket.recv(16) # Note that you limit your filename length to 255 bytes.
if not size:
break
size = int(size, 2)
filename = clientsocket.recv(size)
filesize = clientsocket.recv(32)
filesize = int(filesize, 2)
file_to_write = open(filename, 'wb')
chunksize = 4096
while filesize > 0:
if filesize < chunksize:
chunksize = filesize
data = clientsocket.recv(chunksize)
file_to_write.write(data)
filesize -= len(data)
file_to_write.close()
print 'File received successfully'
serversock.close()
Client:
import socket
import os
import thread
s = socket.socket()
host = socket.gethostname()
port = 9000
s.connect((host, port))
path = "blah"
directory = os.listdir(path)
for files in directory:
print files
filename = files
size = len(filename)
size = bin(size)[2:].zfill(16) # encode filename size as 16 bit binary
s.send(size)
s.send(filename)
filename = os.path.join(path,filename)
filesize = os.path.getsize(filename)
filesize = bin(filesize)[2:].zfill(32) # encode filesize as 32 bit binary
s.send(filesize)
file_to_send = open(filename, 'rb')
l = file_to_send.read()
s.sendall(l)
file_to_send.close()
print 'File Sent'
s.close()
Here the client also sends the size of the file. Both size and filesize are encoded as binary strings (you could do another method). The filename length (size) can take values up to 2^16 and the send file can have up to 2^32 byte (that is 2^filesize).

I believe you're actually receiving all the files' content but then writing them all to one file.
Your server is only accepting a single connection and it writes whatever data it receives into the file until it receives no more data. That won't happen until the client closes its socket at the end.
There are a couple of ways to fix this.
Move the accept call into the server loop and the connect call into the client loop. Have your client connect, send the filename, transfer the entire content of a single file, then close the connection. On the next iteration, do it all over again.
Alternatively, at the beginning of each file, have the client send to the server both the filename to be transferred and the file size (so the server knows how to find the end of the file content). Then write exactly that many bytes to the server. (But see also below as to transmitting the file size.)
I would recommend (1) as more robust and easier to implement.
Second subject: your mechanism for sending the filename is flawed. If I follow it correctly, your program would not work properly if the filename being transmitted begins with a digit as the server will not be able to determine how many bytes are being used to send the filename length. There are two usual ways of sending numbers:
Use the struct module to format a binary integer in a well-defined way. You actually send the "packed" format, and the server would unpack it. It would then know exactly how many bytes long to receive for the filename.
Just send a header line containing the filename followed by a null byte or newline (or some other well-defined defined terminator byte). Then the server can read a byte at a time of the filename until it sees the terminator.

You could create multiple sockets and write using makefile:
server:
import socket
import threading
import time
serversock = socket.socket()
host = socket.gethostname()
port = 9000
serversock.bind((host, port))
serversock.listen(10)
print("Waiting for a connection.....")
def reader(client):
fle = client.makefile('r')
filename = fle.readline()
client.send("Got file {}\n".format(filename))
file_to_write = open(filename.rstrip(), 'wb')
client.send("Starting writing {}\n".format(filename))
file_to_write.write(fle.read())
file_to_write.close()
client.send("Finished writing {}\n".format(filename))
while True:
client, addr = serversock.accept()
print("Got a connection from %s" % str(addr))
client_serve_thread = threading.Thread(target=reader, args=tuple((client,)))
client_serve_thread.start()
time.sleep(0.001)
serversock.close()
client:
import socket
import os
import thread
import os
host = socket.gethostname()
port = 9000
path = "/home/padraic/t"
directory = os.listdir(path)
for file in directory:
s = socket.socket()
s.connect((host, port))
filename = os.path.join(path, file)
s.send(file+"\n")
print(s.recv(1024))
file_to_send = open(os.path.join(path, file), 'rb')
s.send(file_to_send.read())
print('File Sent\n')
file_to_send.close()
rec = s.recv(1024)
print(rec)
s.close()

Related

Speed up file transfer using socket

File transfer using socket stream is too slow. Almost 100kbps. I used the python socket module to make this code. It sends data to the client when the client sends the file name. How can I increase the speed of this thing?
Below is the server code
import socket
import os
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 9999))
server.listen()
client, addr = server.accept()
msg = client.recv(1024).decode()
file = open("Server_files/"+msg, "rb")
file_size = os.path.getsize("Server_files/"+msg)
# client.send("Received_image.png".encode())
client.send(str(file_size).encode())
data = file.read()
client.sendall(data)
client.send(b"<END>")
file.close()
client.close()
Below is the client code
import tqdm
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 9999))
file_name = input("Enter the file name: ")
client.send(file_name.encode())
file_size = client.recv(1024).decode()
print(file_size)
file = open(file_name, "wb")
file_bytes = b""
done = False
progress = tqdm.tqdm(unit="B", unit_scale=True, unit_divisor=1000,
total=int(file_size))
while not done:
data = client.recv(1024)
if file_bytes[-5:] == b"<END>":
done = True
else:
file_bytes += data
progress.update(1024)
file.write(file_bytes)
file.close()
client.close()
Instead of continuously adding incoming data to file_bytes (which requires potentially a lot of RAM, and also requires Python to reallocate the buffer larger multiple times), you should just write the incoming data directly to file as you receive it.
Also it might help to increase your chunk size from 1024 to something larger, maybe 128*1024; that would allow the system calls to do more work in each call.
Here's a complete solution (Python 3.10) that allows multiple files to be downloaded rapidly. It uses socket.makefile to buffer data, with to automatically close sockets, files, and flush tqdm progress, and writes data as received for speed.
Note that TCP is not a messaged-based protocol. It sends bytes and receives bytes in the same order, but not necessarily with the same "breaks". So send('filename') and send('filesize') can be recv(1024) as 'filenamefilesize' or 'filenamefi' and 'lesize' or any other break. So define a protocol:
Server:
read filename followed by '\n'.
If received 0 bytes, connection was closed.
send filesize as a string in base 10 followed by '\n'.
send exactly "filesize" bytes of file data.
repeat.
Client:
send filename followed by '\n'
read filesize followed by '\n', convert to integer of base 10.
read exactly "filesize" bytes of file data
if done, close connection, else repeat.
server.py
import socket
import os
BLOCK = 128 << 10 # 128KB
with socket.socket() as server:
server.bind(('', 9999))
server.listen()
while True:
client, addr = server.accept()
try:
with (client,
client.makefile('rb') as rfile,
client.makefile('wb') as wfile):
while True:
filename = rfile.readline()
if not filename: break
fullname = os.path.join('Server_files', filename.decode().rstrip('\n'))
file_size = os.path.getsize(fullname)
wfile.write(f'{file_size}\n'.encode())
print(f'Sending {fullname}...')
with open(fullname, 'rb') as file:
while data := file.read(BLOCK):
wfile.write(data)
wfile.flush() # make sure anything remaining in makefile buffer is sent.
print(f' Complete ({file_size} bytes).')
except ConnectionResetError:
print('Client aborted.')
client.py
import socket
import tqdm
BLOCK = 1 << 20 # 1MB
with socket.socket() as client:
client.connect(('localhost', 9999))
with (client.makefile('rb') as rfile,
client.makefile('wb') as wfile):
while True:
file_name = input('File name (just ENTER to quit): ')
if not file_name: break
wfile.write(f'{file_name}\n'.encode())
wfile.flush() # make sure makefile buffer is fully sent
file_size = int(rfile.readline().decode())
with (tqdm.tqdm(unit='B',
unit_scale=True,
unit_divisor=1000,
total=file_size) as progress,
open(file_name, 'wb') as file):
remaining = file_size
while remaining:
data = rfile.read(BLOCK if remaining > BLOCK else remaining)
file.write(data)
progress.update(len(data))
remaining -= len(data)
Output example (note download speeds):
File name (just ENTER to quit): bigfile1
100%|██████████████████████████████████████████████████████████| 191M/191M [00:00<00:00, 706MB/s]
File name (just ENTER to quit): bigfile2
100%|██████████████████████████████████████████████████████████| 218M/218M [00:00<00:00, 718MB/s]
File name (just ENTER to quit):

sending multiple images using socket python get sent as one to client

I am capturing screenshots from the server, then sending it to the client, but the images get all sent as one big file to the client that keeps expanding in size. This only happens when i send from one machine to another (I am working on a local netwrok) but when running both client and server from my machine they work fine.
Note: for the client on the other machine, I packaged it into an exe using pyinstaller, since this machine does not have python.
server code:
host="192.168.43.79" # Set the server address to variable host
port=4446 # Sets the variable port to 4446
import time
import pyautogui
from socket import *
import os
s=socket(AF_INET, SOCK_STREAM)
s.bind((host,port))
print("Listening for connections.. ")
q,addr=s.accept()
i = 0
while True:
screenshot = pyautogui.screenshot()
screenshot.save(str(i) + ".jpg")
with open(str(i) + ".jpg", "rb") as f:
data = f.read(4096)
while data:
q.send(data)
data = f.read(4096)
q.send(b"full")
i += 1
time.sleep(0.3)
client code:
host="192.168.43.79" # Set the server address to variable host
port=4446 # Sets the variable port to 4446
from multiprocessing.reduction import recv_handle
from socket import * # Imports socket module
s=socket(AF_INET, SOCK_STREAM) # Creates a socket
s.connect((host,port))
i = 0
while True:
with open(str(i) + "s.jpg", "wb") as f:
recv_data = s.recv(4096)
while recv_data:
f.write(recv_data)
recv_data = s.recv(4096)
if(recv_data == b"full"):
break
i += 1
There various wrong assumptions here which lead to the problem you see. The wrong assumptions are:
that send(data) will write all data It might send less. You need to check the return value or use sendall to be sure.
that a single send in the sender is matched by exactly a single recv in the recipientTCP is only an unstructured byte stream. send does not add message semantics, so a single send might lead to multiple recv, multiple send might lead to a single recv etc. Specifically send("data") followed by send("full") might be recv(4096) as "datafull", thus missing your code to detect end of image.
As for why does it work on the local machine but not on the remote - the chance in the latter case is higher that send get combined together and recv as one.
As stated by Steffen Ulrich you should use sendall for sending and for receiving we create a specialized function my_recv that will repeatedly call socket.recv until the expected number of bytes have been received. Also, a 4-byte header (you can make the length greater if your file sizes warrant this) that contains a binary representation of the file length precedes the sending of the actual file data. In this way the client knows exactly how much data it should receive for each file.
Server Code
host="192.168.43.79" # Set the server address to variable host
port=4446 # Sets the variable port to 4446
import time
import pyautogui
from socket import *
import os
s=socket(AF_INET, SOCK_STREAM)
s.bind((host,port))
s.listen(1) # This should be called
print("Listening for connections.. ")
q,addr=s.accept()
i = 0
while True:
screenshot = pyautogui.screenshot()
screenshot.save(str(i) + ".jpg")
with open(str(i) + ".jpg", "rb") as f:
# Get length by positioning to end of file
image_length = f.seek(0, 2)
f.seek(0, 0) # Seek back to beginning of file
# Convert image length to a 4-byte array:
image_length_bytes = image_length.to_bytes(4, 'big')
q.sendall(image_length_bytes)
data = f.read(4096)
while len(data):
q.sendall(data)
data = f.read(4096)
i += 1
Client Code
host="192.168.43.79" # Set the server address to variable host
port=4446 # Sets the variable port to 4446
from multiprocessing.reduction import recv_handle
from socket import * # Imports socket module
s=socket(AF_INET, SOCK_STREAM) # Creates a socket
s.connect((host,port))
def my_recv(msg_length):
chunks = []
bytes_to_recv = msg_length
while bytes_to_recv:
chunk = s.recv(bytes_to_recv)
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_to_recv -= len(chunk)
return b''.join(chunks)
i = 0
while True:
image_length_bytes = my_recv(4)
image_length = int.from_bytes(image_length_bytes, 'big')
with open(str(i) + "s.jpg", "wb") as f:
bytes_to_recv = image_length
while bytes_to_recv:
recv_data = my_recv(min(4096, bytes_to_recv))
f.write(recv_data)
bytes_to_recv -= len(recv_data)
i += 1

I can not get the data from my server after having sent a file thought sockets

I have a problem when I try to send an Acknowledgment after receiving data.
To resume the situation, I have a client that have a file to send to my server that is listening. When the server receive this file it returns an acknowledgment file. And here is my problem. When my server send the ACK file my client don't get it and just stand here and don't do anything else.
server.py
import socket
import signal
import os
# "all" interfaces
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 8000
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"
# Setting Dicionnaries for HL7 ACK Requirements
MSH = {3:'HOSPITAL', 4:'RESULTS', 5:'LAB400', 6:'RESULTS',7:'20201030084524',9:'ACK', 10:'1452357', 11:'P',12:'2.2', 15:'AL', 16:'NE', 17:'CHE'}
MSA = {1:'AA', 2:'1722178'}
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# test the binding
try:
socket.bind((SERVER_HOST, SERVER_PORT))
except socket.error as error:
print('Bind failed. Error Code : '
+ str(error[0]) + ' Message '
+ error[1])
exit()
def signal_handler(sign, frame):
print('[*] Shutting down')
exit(0)
while signal.signal(signal.SIGINT, signal_handler):
# connection limit(5 connection try then deny)
socket.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
# accept the connection if there is any
client_socket, address = socket.accept()
# Below code is executed if sender is connected
print(f"[+] {address} is connected.")
# get what the client is sending
received = client_socket.recv(BUFFER_SIZE).decode()
filename, fileSize = received.split(SEPARATOR)
#convert to integer
fileSize = int(fileSize)
# remove absolute path if there is
filename = os.path.basename(filename)
# start receiving the file from the socket and writing to the file stream
with open(f".\\Files\\{filename}", "wb") as f:
while True:
# read 1024 bytes from the socket (receive)
bytes_read = client_socket.recv(BUFFER_SIZE)
if not bytes_read:
# file transmitting is done
print(f"[+] File transfert is done")
print(f"[+] File saved")
break
# write to the file the bytes we just received
f.write(bytes_read)
myfile = open(".\\Files\\ack.hl7", "rb")
client_socket.send(myfile.read())
client_socket.close()
socket.close
client.py
import socket
import os
import random
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096
HOST = "127.0.0.1"
PORT = 8000
files = ["test1.HL7","test2.HL7","test3.HL7","test4.HL7","test5.HL7","test6.HL7","test7.HL7","test8.HL7"]
# fileName = f".\\ClientFiles\\{files[random.randrange(1,8)]}"
fileName = f".\\ClientFiles\\{files[0]}"
filesize = os.path.getsize(fileName)
socket = socket.socket()
print(f"[+] Connecting to {HOST}:{PORT}")
socket.connect((HOST, PORT))
print("[+] Connected.")
socket.send(f"{fileName}{SEPARATOR}{filesize}".encode())
# opening file
with open(fileName, "rb") as f:
while True:
# reading bytes
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
# Transmitting is done
break
# send all the buffer
socket.sendall(bytes_read)
print(f"[+] File {fileName} sent")
data = socket.recv(BUFFER_SIZE)
print(data)
print("[*] Closing")
socket.close()
I cannot figure out why it doesn't work
Here is my files that need to be transferred(it's some HL7 V2.5.1 btw)
Ack.hl7
MSH|^~\&|HOSPITAL|RESULTS|LAB400|RESULTS|20201030084524||ACK|1452357|P|2.2
MSA|AA|1722178
testFile.hl7
MSH|^~\&|ADT1|MCM|LABADT|MCM|198808181126|SECURITY|ADT^A04|MSG00001|P|2.4
EVN|A01-|198808181123
PID|||PATID1234^5^M11||JONES^WILLIAM^A^III||19610615|M-||2106-3|1200 N ELM STREET^^GREENSBORO^NC^27401-1020|GL|(919)379-1212|(919)271-3434~(919)277-3114||S||PATID12345001^2^M10|123456789|9-87654^NC
NK1|1|JONES^BARBARA^K|SPO|||||20011105
NK1|1|JONES^MICHAEL^A|FTH
PV1|1|I|2000^2012^01||||004777^LEBAUER^SIDNEY^J.|||SUR||-||1|A0-
AL1|1||^PENICILLIN||PRODUCES HIVES~RASH
AL1|2||^CAT DANDER
DG1|001|I9|1550|MAL NEO LIVER, PRIMARY|19880501103005|F||
PR1|2234|M11|111^CODE151|COMMON PROCEDURES|198809081123
ROL|45^RECORDER^ROLE MASTER LIST|AD|CP|KATE^SMITH^ELLEN|199505011201
GT1|1122|1519|BILL^GATES^A
IN1|001|A357|1234|BCMD|||||132987
IN2|ID1551001|SSN12345678
ROL|45^RECORDER^ROLE MASTER LIST|AD|CP|KATE^ELLEN|199505011201
What I've tried so far
On my client
I've tried to recreate a socket in the case that it wasn't able to respond
try:
data = socket.recv(BUFFER_SIZE)
print(data)
except:
# recreate the socket and reconnect
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect(HOST, PORT)
data = socket.recv(BUFFER_SIZE)
print(data)
I could reproduce and understand your problem.
The underlying cause is that TCP is a stream protocol. That means that the only guarantee is that all the bytes that are sent from one side will the received in the same ordre by the peer. But packets mays be concatenated or splitted by any element on the network, including the protocol stack of either side.
So in server.py, this is wrong:
# get what the client is sending
received = client_socket.recv(BUFFER_SIZE).decode()
filename, fileSize = received.split(SEPARATOR)
#convert to integer
fileSize = int(fileSize)
because received can contain the beginning of the data...
The robust way would be:
# get what the client is sending
received = client_socket.recv(BUFFER_SIZE)
filename, bytes_read = received.split(SEPARATOR.encode())
fileSize = bytes(itertools.takewhile(
lambda i: bytes((i,)).isdigit(), bytes_read))
bytes_read = bytes_read[len(fileSize):]
#convert to integer
fileSize = int(fileSize)
filename = filename.decode()
And you will have the beginning of the data (as bytes) in bytes_read and should write it immediately:
# start receiving the file from the socket and writing to the file stream
with open(f".\\Files\\{filename}", "wb") as f:
f.write(bytes_read)
while True:
...
But that is not all. Still in server.py the reading loop will not return an empty buffer until the peer closes or better shutdowns the socket.
So in client.py you must signal the end of transmission:
print(f"[+] File {fileName} sent")
socket.shutdown(SHUT_WR) # tells peer that nothing will be sent any more
data = socket.recv(BUFFER_SIZE)

How to send file in python over network without loosing data?

I'm trying to send a file data.txt that contains this words 'hello world' over my network using 2 files in Python, one called server.py :
import socket
import tqdm
import os
# device's IP address
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 5001
# receive 4096 bytes each time
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"
# create the server socket
# TCP socket
s = socket.socket()
# bind the socket to our local address
s.bind((SERVER_HOST, SERVER_PORT))
# enabling our server to accept connections
# 5 here is the number of unaccepted connections that
# the system will allow before refusing new connections
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
# accept connection if there is any
client_socket, address = s.accept()
# if below code is executed, that means the sender is connected
print(f"[+] {address} is connected.")
# receive the file infos
# receive using client socket, not server socket
received = client_socket.recv(BUFFER_SIZE).decode()
filename, filesize = received.split(SEPARATOR)
# remove absolute path if there is
filename = os.path.basename(filename)
# convert to integer
filesize = int(filesize)
# start receiving the file from the socket
# and writing to the file stream
progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "wb") as f:
while True:
# read 1024 bytes from the socket (receive)
bytes_read = client_socket.recv(BUFFER_SIZE)
if not bytes_read:
# nothing is received
# file transmitting is done
break
# write to the file the bytes we just received
f.write(bytes_read)
# update the progress bar
progress.update(len(bytes_read))
progress.close()
# close the client socket
client_socket.close()
# close the server socket
s.close()
and the other one called client.py :
import socket
import tqdm
import os
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096 # send 4096 bytes each time step
# the ip address or hostname of the server, the receiver
host = "192.168.1.12"
# the port, let's use 5001
port = 5001
# the name of file we want to send, make sure it exists
filename = "data.txt"
# get the file size
filesize = os.path.getsize(filename)
# create the client socket
s = socket.socket()
print(f"[+] Connecting to {host}:{port}")
s.connect((host, port))
print("[+] Connected.")
# send the filename and filesize
s.send(f"{filename}{SEPARATOR}{filesize}".encode())
# start sending the file
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
while True:
# read the bytes from the file
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
# file transmitting is done
break
# we use sendall to assure transimission in
# busy networks
s.sendall(bytes_read)
# update the progress bar
progress.update(len(bytes_read))
# close the socket
s.close()
Here is what I tried:
I checked the code over and over for any mistake. The problem is that the file is received empty with 0 bytes although it contained a string before sending.
How can I fix this problem, any help or suggestion will be much appreciated.
It seems you're running server and client in the same directory, and the server truncates the file before the client gets to read from it.
it works pefect for me with hello world but if you want to send a binary file maybe you can try base 64

Decode not working properly and while loop not breaking correctly python

This is a file transfer application using TCP sockets in Python. The file-transfer protocol will in- clude a server called ftps.py and a client called ftpc.py.
The file-transfer application will use a simple protocol. The first 4 bytes (in network byte order) will contain the number of bytes in the file to follow. The next 20 bytes will contain the name of the file (assume the name fits in 20 bytes). The rest of the bytes in the TCP stream to follow will contain the data in the file.
I am running the client program and the server program on separate machines, but i have two errors:
1) The when i encode the filename and sent it to the socket, when the server side receives it and decodes it, the filename isn't correct
2) The server side seems to be stuck in a while loop and i don't know why
Client
import socket
import sys
import os
filename=sys.argv[2]
print filename
if len(sys.argv) > 1 :
print('Trying to connect...')
s = socket.socket()
ip_add=(sys.argv[1])
print(ip_add)
s.connect((ip_add, 4000))
print('Connected. Wating for command.')
while True:
cmd = s.recv(24)
if cmd == 'getsize':
print('"getsize" command received.')
statinfo=os.stat(filename)
byte_size=statinfo.st_size
size_str=str(byte_size)
s.sendall(size_str)
if cmd == 'getfilename':
print('"getfilename" command received.')
formatted_name = filename.rjust(20)
fname = formatted_name.lstrip()
print(fname)
encoded_filename=fname.encode('utf-8')
s.sendall(encoded_filename)
if cmd == 'getfile':
print('"getfile" command received. Going to send file.')
file_input = open(sys.argv[2], 'rb')
while True:
buff = file_input.read(512)
if len(buff) == 0:
break
s.sendall(buff)
print('File transmission done.')
if cmd == 'end':
print('"end" command received. Teminate.')
break
file_input.close()
f.close()
Server
import socket
import os
import sys
save_path='recv/'
print('Waiting for clinet to connect...')
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.bind(('', 4000))
c.listen(1)
s, a = c.accept()
print('Connected. Going to receive file.')
s.sendall('getsize')
filesize_str = s.recv(4)
size_bytes=filesize_str.decode()
print(size_bytes)
s.sendall('getfilename')
byte_var = s.recv(20)
filename=byte_var.decode('utf-8')
output = os.path.join(save_path, filename)
f = open(output, 'wb')
print('Filename: ' + filename)
while True:
s.sendall('getfile')
while True:
data = s.recv(512)
if not data:
break
f.write(data)
break
s.sendall('end')
print('File received.')
s.close()
c.close()
f.close()
Here is the terminal output for the server program:
% python ftps.py
Waiting for clinet to connect...
Connected. Going to receive file.
1797
Filename: 55
Client output:
% python ftpc.py 164.107.113.20 2.jpg
2.jpg
Trying to connect...
164.107.113.20
Connected. Wating for command.
"getsize" command received.
"getfilename" command received.
2.jpg
"getfile" command received. Going to send file.
File transmission done.
where it says Filename: 55, it should be Filename:2.jpg
and the program is stuck in a loop at this point.. any one know why this is happening?

Categories

Resources