Python TCP server/client for transferring files - python

I was trying to make a TCP server/client in order to transfer files between the two. My code looks like this (its messy) for now. When sending a GET command I want to receive a file from the server which works but only if I ^C to close the client (the file is created but nothing is written in it until I close the client). When I send a SEND command to get a file from the server (machine running the server) it works but just because I shutdown the socket after that. I want to keep the socket connected after sending the file.
Here is the code that is used for this:
server.py
elif msg[:4] == 'file':
client_command = msg[5:9]
if client_command == 'GET ':
file_name = msg[9:]
f = open(file_name, "rb")
l = f.read(self.BUFF_SIZE)
while(l):
self.send_info(l)
l = f.read(self.BUFF_SIZE)
f.close()
elif client_command == 'SEND':
file_name = msg[10:]
f = open(file_name, "wb")
l = self.recv_info()
while(l):
f.write(l)
l = self.recv_info()
f.close()
def send_info(self, msg):
info = bytes(msg)
send = self.client_socket.sendall(info)
return send
def recv_info(self):
recv = self.client_socket.recv(self.BUFF_SIZE)
return recv
client.py
answer = input()
elif answer[:4] == 'file':
s.send(answer.encode('iso-8859-1'))
command = answer[5:9]
if command == 'GET ':
fileName = answer[9:]
f = open(fileName, 'wb')
l = s.recv(2048)
while(l):
f.write(l)
l = s.recv(2048)
f.close()
elif command == 'SEND':
fileName = answer[10:]
f = open(fileName, 'rb')
l = f.read(2048)
while (l):
s.send(l)
l = f.read(2048)
f.close()
s.shutdown(socket.SHUT_WR)
I will change the way I'm taking care of the filename and move away from slicing once I'm sure the transferring works.
I probably just don't understand how the transfer should be made but if anyone could correct my code or explain how it should be tin order to be functional. I just want to be able to send and transfer files without the socket closing (shutdown) so that I don't have to reconnect the client after every command and without having to close the client to finish transferring a file. I can add more of the code if need be.
Thanks for any help.

The problem might be the file is being buffered. If you want to enforce the file will be written right after you have received, you can use the flush method:
f = open(fileName, 'wb')
l = s.recv(2048)
while(l):
f.write(l)
l = s.recv(2048)
f.flush()
f.close()
Note: I Highly suggest you use the with statement, to ensure the file is always closed:
with open(filename, 'wb') as f:
l = s.recv(2048)
while(l):
f.write(l)
l = s.recv(2048)
f.flush()

Related

Server's Data is not getting received by Client in Python Socket

I am trying to create a function that allows the client to download a file from the server. Below oare the relevant portions of the code. I have gotten to the point where a text file with the same name is created in the client folder, but it is just empty with no data. The programs get to the "received file line" but nothin else.
Client Code:
elif cmd == "DOWN":
filename = data[1]
print(filename)
client.send(filename.encode(FORMAT))
f = open("client/" + filename, 'wb')
while True:
print("receiving data")
data = client.recv(1024).decode(FORMAT)
if not data:
break
f.write(data)
print("Data: %s", (data))
f.close()
Server Code:
elif cmd == "DOWN":
file = conn.recv(1024).decode(FORMAT)
f = open("server/"+file, 'rb')
l = f.read(1024)
while (l):
conn.send(l.encode(FORMAT))
print("send data", repr(1))
l = f.read(1024)
f.close()
print("done sending")
Output:
Welcome to the server
> DOWN abc.txt
abc.txt
recieving data
The program enters the loop to receive the data, but nothing else. Any help would be appreciated. Thank you.

EOL while scanning string literal [in python sockets]

I'm a newbie, and this is my first question on stackoverflow, so with that said, here's my question
CLIENT CODE
import socket
cs = socket.socket()
ADDR = ('192.168.29.139',9999)
cs.connect(ADDR)
l = int(cs.recv(2048).decode())
data = cs.recv(l).decode()
data = eval(data)
cont = data["file"]["cont"]
f = open(data['file']['name'] + data['file']['ext'], "wb")
f.write(cont)
f.close()
SERVER CODE
## SERVER SIDE
import socket
ss = socket.socket()
ADDR = ('192.168.29.139',9999)
ss.bind(ADDR)
ss.listen()
conn, addr = ss.accept()
msg = input("Enter message: ")
filepath = input("Enter filepath: ")
fileName = input("Enter filename : ")
fileExt = input("Enter fileExt:" )
f = open(filepath,"rb")
r = f.read()
f.close()
fileDict = {"name": fileName, "ext": fileExt, "cont": r}
msg_dict = {"msg":msg, "file": fileDict}
msg_dict = str(msg_dict).encode()
conn.send(str(len(msg_dict)).encode())
conn.send(msg_dict)
This method works totally fine when I transfer files within the same computer (even bigger files, like several GBs, in this test I was using the windows 7 test video, that was about 25MB) but when i use it on LAN to transfer the same file, between two computers within the same network it shows an error
right during this statement
data = eval(data)
the error was, after printing so many lines of characters like \xo... and empty lines
EOL while scanning string literal ^
using pickle also gave error
Thank you for reading... Please HELP!

how to create an exact copy of a non-text binary file in python

The program should copy the content of in_file_name to the out_file_name. This is what I have but it keeps crashing.
in_file_name = input('Enter an existing file: ')
out_file_name = input('Enter a new destination file: ')
try:
in_file = open(in_file_name, 'r')
except:
print('Cannot open file' + ' ' + in_file_name)
quit()
size = 0
result = in_file.read(100)
while result!= '':
size += len(result)
result = in_file.read(100)
print(size)
in_file.close()
try:
out_file = open(out_file_name, 'a')
except:
print('Cannot open file' + ' ' + out_file_name)
quit()
out_file.close()
You can use shutil for this purpose
from shutil import copyfile
in_file_name = input('Enter an existing file: ')
out_file_name = input('Enter a new destination file: ')
try:
copyfile(in_file_name, out_file_name)
except IOError:
print("Seems destination is not writable")
There's 2 things:
There's better ways to do this (like using shutil.copy and various other functions in the standard library to copy files)
If it's a binary file, open it in "binary" mode.
Anyway, here's how to do it if you're sticking to manually doing it.
orig_file = "first.dat"
copy_file = "second.dat"
with open(orig_file, "rb") as f1:
with open(copy_file, "wb") as f2:
# Copy byte by byte
byte = f1.read(1)
while byte != "":
f2.write(byte)
byte = f1.read(1)
Using std library functions: How do I copy a file in python?
Here is what I did. Using while ch != "": gave me a hanging loop, but it did copy the image. The call to read returns a falsy value at EOF.
from sys import argv
donor = argv[1]
recipient = argv[2]
# read from donor and write into recipient
# with statement ends, file gets closed
with open(donor, "rb") as fp_in:
with open(recipient, "wb") as fp_out:
ch = fp_in.read(1)
while ch:
fp_out.write(ch)
ch = fp_in.read(1)

Trying to create a crude send/receive through TCP in python

So far I can send files to my "fileserver" and retrieve files from there as well. But i can't do both at the same time. I have to comment out one of the other threads for them to work. As you will see in my code.
SERVER CODE
from socket import *
import threading
import os
# Send file function
def SendFile (name, sock):
filename = sock.recv(1024)
if os.path.isfile(filename):
sock.send("EXISTS " + str(os.path.getsize(filename)))
userResponse = sock.recv(1024)
if userResponse[:2] == 'OK':
with open(filename, 'rb') as f:
bytesToSend = f.read(1024)
sock.send(bytesToSend)
while bytesToSend != "":
bytesToSend = f.read(1024)
sock.send(bytesToSend)
else:
sock.send('ERROR')
sock.close()
def RetrFile (name, sock):
filename = sock.recv(1024)
data = sock.recv(1024)
if data[:6] == 'EXISTS':
filesize = long(data[6:])
sock.send('OK')
f = open('new_' + filename, 'wb')
data = sock.recv(1024)
totalRecieved = len(data)
f.write(data)
while totalRecieved < filesize:
data = sock.recv(1024)
totalRecieved += len(data)
f.write(data)
sock.close()
myHost = ''
myPort = 7005
s = socket(AF_INET, SOCK_STREAM)
s.bind((myHost, myPort))
s.listen(5)
print("Server Started.")
while True:
connection, address = s.accept()
print("Client Connection at:", address)
# u = threading.Thread(target=RetrFile, args=("retrThread", connection))
t = threading.Thread(target=SendFile, args=("sendThread", connection))
# u.start()
t.start()
s.close()
CLIENT CODE
from socket import *
import sys
import os
servHost = ''
servPort = 7005
s = socket(AF_INET, SOCK_STREAM)
s.connect((servHost, servPort))
decision = raw_input("do you want to send or retrieve a file?(send/retrieve): ")
if decision == "retrieve" or decision == "Retrieve":
filename = raw_input("Filename of file you want to retrieve from server: ") # ask user for filename
if filename != "q":
s.send(filename)
data = s.recv(1024)
if data[:6] == 'EXISTS':
filesize = long(data[6:])
message = raw_input("File Exists, " + str(filesize)+"Bytes, download?: Y/N -> ")
if message == "Y" or message == "y":
s.send('OK')
f = open('new_' + filename, 'wb')
data = s.recv(1024)
totalRecieved = len(data)
f.write(data)
while totalRecieved < filesize:
data = s.recv(1024)
totalRecieved += len(data)
f.write(data)
print("{0: .2f}".format((totalRecieved/float(filesize))*100)) + "% Done" # print % of download progress
print("Download Done!")
else:
print("File does not exist!")
s.close()
elif decision == "send" or decision == "Send":
filename = raw_input("Filename of file you want to send to server: ")
if filename != "q":
s.send(filename)
if os.path.isfile(filename):
s.send("EXISTS " + str(os.path.getsize(filename)))
userResponse = s.recv(1024)
if userResponse[:2] == 'OK':
with open(filename, 'rb') as f:
bytesToSend = f.read(1024)
s.send(bytesToSend)
while bytesToSend != "":
bytesToSend = f.read(1024)
s.send(bytesToSend)
else:
s.send('ERROR')
s.close()
s.close()
I'm still new to programming, so this is quite tough for me. All in all i'm just trying to figure out how to send AND receive files without having to comment out the bottom threads in my SERVER CODE.
Please and thank you!
On the serverside, you're trying to use the same connection for your two threads t and u.
I think it might work if you listened for another connection in your while True: loop on the server, after you started your first thread.
I always use the more high-level socketserver module (Python Doc on socketserver), which also natively supports Threading. I recommend checking it out!
By the way, since you do a lot of if (x == 'r' or x == 'R'): you could just do if x.lower() == 'r'
just made an if statement sending a True or False and that will decide which thread to execute.

ironPython - python socket file transfer, typeError

I'm trying to send a binary file from a client that runs on ironPython 2.7.4 to a server that runs on cpython 2.7.6 on a linuxbox. I followed this example, however when the server starts writing the file (first call to f.write), I get an Error:
TypeError: must be string or buffer, not int
Here the I think relevant pieces of the code.
server:
def recvall(self, count):
msgparts = []
while count > 0:
newbuf = self.conn.recv(count)
if not newbuf: return None
msgparts.append(newbuf)
count -= len(newbuf)
#print "%i bytes left" % count
return "".join(msgparts)
#receive file, write out
f = open(fname, 'wb')
chunk = self.recvall(1024)
while (chunk):
f.write(1024) #<-- error happens here.
chunk = self.recvall(1024)
f.close()
client:
f = open(fname, 'rb')
chunk = f.read(1024)
while (chunk):
self.conn.send(chunk)
chunk = f.read(1024)
f.close()
conn is the socket connection - this works, I can transfer pickled dicts successfully.
Any hints?
thanks and regards,
Dominic
f.write(chunk)
should do it (instead of f.write(1024).
As the error message states, f.write expects a string parameter, and 1024 is clearly an int

Categories

Resources