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.
Related
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'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!
I am facing a problem writing a program to send contents of a folder over the network by using Python. There are a lot of examples out there, all the examples I found are assuming the receiver side knew name of the file he want to receive. The program I am trying to do assuming that the receiver side agree to receive a files and there is no need to request a file by its name from the server. Once the connection established between the server and the client, the server start send all files inside particular folder to the client. Here is a image to show more explanation:example here
Here are some programs that do client server but they send one file and assume the receiver side knew files names, so the client should request a file by its name in order to receive it.
Note: I apologies for English grammar mistakes.
https://www.youtube.com/watch?v=LJTaPaFGmM4
http://www.bogotobogo.com/python/python_network_programming_server_client_file_transfer.php
python socket file transfer
Here is best example I found:
Server side:
import sys
import socket
import os
workingdir = "/home/SomeFilesFolder"
host = ''
skServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
skServer.bind((host, 1000))
skServer.listen(10)
print "Server Active"
bFileFound = 0
while True:
Content, Address = skServer.accept()
print Address
sFileName = Content.recv(1024)
for file in os.listdir(workingdir):
if file == sFileName:
bFileFound = 1
break
if bFileFound == 0:
print sFileName + " Not Found On Server"
else:
print sFileName + " File Found"
fUploadFile = open("files/" + sFileName, "rb")
sRead = fUploadFile.read(1024)
while sRead:
Content.send(sRead)
sRead = fUploadFile.read(1024)
print "Sending Completed"
break
Content.close()
skServer.close()
Client side:
import sys
import socket
skClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
skClient.connect(("ip address", 1000))
sFileName = raw_input("Enter Filename to download from server : ")
sData = "Temp"
while True:
skClient.send(sFileName)
sData = skClient.recv(1024)
fDownloadFile = open(sFileName, "wb")
while sData:
fDownloadFile.write(sData)
sData = skClient.recv(1024)
print "Download Completed"
break
skClient.close()
if there is a way to eliminate this statement from the client side:
sFileName = raw_input("Enter Filename to download from server : ")
and make the server side send all files one by one without waiting for the client to pick a file.
Here's an example that recursively sends anything in the "server" subdirectory to a client. The client will save anything received in a "client" subdirectory. The server sends for each file:
The path and filename relative to the server subdirectory, UTF-8-encoded and terminated with a newline.
The file size in decimal as a UTF-8-encoded string terminated with a newline.
Exactly "file size" bytes of file data.
When all files are transmitted the server closes the connection.
server.py
from socket import *
import os
CHUNKSIZE = 1_000_000
sock = socket()
sock.bind(('',5000))
sock.listen(1)
while True:
print('Waiting for a client...')
client,address = sock.accept()
print(f'Client joined from {address}')
with client:
for path,dirs,files in os.walk('server'):
for file in files:
filename = os.path.join(path,file)
relpath = os.path.relpath(filename,'server')
filesize = os.path.getsize(filename)
print(f'Sending {relpath}')
with open(filename,'rb') as f:
client.sendall(relpath.encode() + b'\n')
client.sendall(str(filesize).encode() + b'\n')
# Send the file in chunks so large files can be handled.
while True:
data = f.read(CHUNKSIZE)
if not data: break
client.sendall(data)
print('Done.')
The client creates a "client" subdirectory and connects to the server. Until the server closes the connection, the client receives the path and filename, the file size, and the file contents and creates the file in the path under the "client" subdirectory.
client.py
from socket import *
import os
CHUNKSIZE = 1_000_000
# Make a directory for the received files.
os.makedirs('client',exist_ok=True)
sock = socket()
sock.connect(('localhost',5000))
with sock,sock.makefile('rb') as clientfile:
while True:
raw = clientfile.readline()
if not raw: break # no more files, server closed connection.
filename = raw.strip().decode()
length = int(clientfile.readline())
print(f'Downloading {filename}...\n Expecting {length:,} bytes...',end='',flush=True)
path = os.path.join('client',filename)
os.makedirs(os.path.dirname(path),exist_ok=True)
# Read the data in chunks so it can handle large files.
with open(path,'wb') as f:
while length:
chunk = min(length,CHUNKSIZE)
data = clientfile.read(chunk)
if not data: break
f.write(data)
length -= len(data)
else: # only runs if while doesn't break and length==0
print('Complete')
continue
# socket was closed early.
print('Incomplete')
break
Put any number of files and subdirectories under a "server" subdirectory in the same directory as server.py. Run the server, then in another terminal run client.py. A client subdirectory will be created and the files under "server" copied to it.
So... I've decided I've posted enough in comments and I might as well post a real answer. I see three ways to do this: push, pull, and indexing.
Push
Recall the HTTP protocol. The client asks for a file, the server locates it, and sends it. So get a list of all the files in a directory and send them all together. Better yet, tar them all together, zip them with some compression algorithm, and send that ONE file. This method is actually pretty much industry standard among Linux users.
Pull
I identifed this in the comments, but it works like this:
Client asks for directory
Server returns a text file containing the names of all the files.
Client asks for each file.
Index
This technique is the least mutable of the three. Keep an index of all the files in the directory, named INDEX.xml (funny enough, you could model the entire directory tree in xml.) your client will request the xml file, then walk the tree requesting other files.
you need to send os.listdir() by using json.dumps() and encode it as utf-8
at client side you need to decode and use json.loads() so that list will be transfer to client
place sData = skClient.recv(1024) before sFileName = raw_input("Enter Filename to download from server : ") so that the server file list can be display
you can find at here its a interesting tool
https://github.com/manoharkakumani/mano
from socket import *
import sys
# Create a server socket, bind it to a port and start listening
tcpSerSock = socket(AF_INET, SOCK_STREAM)
serverPort = 12000
tcpSerSock.bind(('', serverPort))
tcpSerSock.listen(1)
print ("Server ready")
while 1==1:
# Start receiving data from the client. e.g. request = "GET http://localhost:portNum/www.google.com"
tcpCliSock, addr = tcpSerSock.accept()
print ('Received a connection from:', addr)
request = str(tcpCliSock.recv(1024).decode())
print ("Requested " + request)
# Extract the file name from the given request
fileName = request.split()[1]
print ("File name is " + fileName)
fileExist = "false"
fileToUse = "/" + fileName
print ("File to use: " + fileToUse)
try:
# Check wether the file exist in the cache. The open will fail and go to "except" in case the file doesn't exist. Similar to try/catch in java
f = open(fileToUse[1:], "r")
outputData = f.readlines()
fileExist = "true"
# ProxyServer finds a cache hit and generates a response message
tcpCliSock.send("HTTP/1.1 200 OK\r\n")
tcpCliSock.send("Content-Type:text/html\r\n")
tcpCliSock.send(outputData)
print ('This was read from cache')
except IOError:
if fileExist == "false":
# Create a socket on the proxyserver
c = socket(AF_INET, SOCK_STREAM)
hostn = fileName.replace("www.","",1) #max arg specified to 1 in case the webpage contains "www." other than the usual one
print (hostn)
try:
# Connect to the socket to port 80
c.bind(('', 80))
# Create a temporary file on this socket and ask port 80 for the file requested by the client
print("premake")
fileObj = c.makefile('r', 0)
print("postmake")
fileObj.write("GET " + "http://" + fileName + " HTTP/1.1\r\n")
# Read the response into buffer
print("post write")
buff = fileObj.readlines()
# Create a new file in the cache for the requested file.
tmpFile = open("./" + filename,"wb")
# Send the response in the buffer to both client socket and the corresponding file in the cache
for line in buff:
tmpFile.write(line)
tcpCliSock.send(tmpFile)
except:
print ("Illegal request")
break
else:
# HTTP response message for file not found
print("HTTP response Not found")
# Close the client and the server sockets
tcpCliSock.close()
#tcpSerSock.close()
The code never manages to execute the 'try' entered in 'except IOError'. The problem seems to be the socket.makefile(mode, buffsize) function, which has poor documentation for python 3. I tried passing 'rwb', 'r+', 'r+b' and so on to the function, but at most I would manage to create the file and be unable to write to it thereafter.
This is a python2.7 vs python3 issue. While makefile('r',0) works in python 2.7, you need makefile('r',None) in python3.
From the documentation for python2.7:
socket.makefile([mode[, bufsize]])
From the documentation for python3:
socket.makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None)
I am trying to program compilation server which compiles a C program sent by client and returns an object file which can then be linked and executed at the client. Here are my client and server programs respectively
client.py:
# Compilation client program
import sys, socket, string
File = raw_input("Enter the file name:")
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssock.connect(('localhost', 5000))
csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
csock.connect(('localhost', 5001))
f = open(File, "rb")
data = f.read()
f.close()
ssock.send(File) #send filename
ssock.send(data) #send file
fd=raw_input("Enter a key to start recieving object file:")
data=csock.recv(1024) #receive status
if data=="sucess\n":
File=File.replace(".c",".o") #objectfile name
print "Object file, "+File+", recieved sucessfully"
else:
print "There are compilation errors in " + File
File="error.txt" #errorfile name
print "Errors are reported in the file error.txt"
fobj=open(File,"wb")
while 1:
data=ssock.recv(1024) # if any error in c sourcefile then error gets
# eported in errorfile "error.txt" else objectfile is
# returned from server
if not data:break
fobj.write(data)
fobj.close()
ssock.close()
csock.close()
server.py
#Compilation Server program
import subprocess
import socket, time, string, sys, urlparse, os
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssock.bind(('', 5000))
ssock.listen(2)
print 'Server Listening on port 5000'
csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
csock.bind(('', 5001))
csock.listen(2)
print 'Control server listening on port 5001'
client, claddr = ssock.accept()
controlsoc, caddr = csock.accept()
filename=client.recv(1024) #receive filename
print filename
############### This code is not working, i'm not getting the reason #######
############### I want to receive a file more than 1KB from client #######
f = open(filename,"wb") #receive file======
while 1:
data = client.recv(1024)
if not data: break
f.write(data)
f.close()
###############
###############
data="gcc -c " + filename + " 2> error.txt" #shell command to execute c source file
#report errors if any to error.txt
from subprocess import call
call(data,shell=True) #executes the above shell command
fil = filename.replace(".c",".o")
if (os.path.isfile(fil))== True: #test for existence of objectfile
data = "sucess\n" #no objectfile => error in compilation
filename = filename.replace(".c",".o")
else:
data = "unsucessful\n"
print data+"hi"
filename = "error.txt"
controlsoc.send(data)
f = open(filename,"rb")
data=f.read()
f.close()
print data
client.send(data)
client.close()
controlsoc.close()
I'm not able to recieve files of multiple KB. Is there any flaw in my code or how should i modify my code in order to achieve my objective of coding a compilation server.
Please help me with this regard..Thanks in advance
The problem here is you assume that ssock.send(File) will result in filename=client.recv(1024) reading exactly the filename and not more, but in fact the receiving side has no idea where the filename ends and you end up getting the file name and part of the data in the filename variable.
TCP connection is a bi-directional stream of bytes. It doesn't know about boundaries of your messages. One send might correspond to more then one recv on the other side (and the other way around). You need an application-level protocol on top of raw TCP.
The easiest in your case would be to send a text line in the form file-size file-name\n as a header. This way your server would be able to not only separate header from file data (via newline) but also know how many bytes of file content to expect, and reuse same TCP connection for multiple files.