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!
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'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
I have created a proxy server that receives requests, searches for the requested file in its cache. If available it returns the cached file. If file is not available then it will ask the actual server, gets it, stores it in the cache and returns the file to the client.
Following is the code:
from socket import *
import sys
if len(sys.argv) <= 1:
print 'Usage : "python ProxyServer.py server_ip"\n[server_ip : It is the IP Address Of Proxy Server'
sys.exit(2)
# Create a server socket, bind it to a port and start listening
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind((sys.argv[1], 8888))
tcpSerSock.listen(100)
while 1:
# Strat receiving data from the client
print 'Ready to serve...'
tcpCliSock, addr = tcpSerSock.accept()
print 'Received a connection from:', addr
message = tcpCliSock.recv(1024)
print message
# Extract the filename from the given message
print message.split()[1]
filename = message.split()[1].partition("/")[2]
print filename
fileExist = "false"
filetouse = "/" + filename
print filetouse
try:
# Check wether the file exist in the cache
f = open(filetouse[1:], "r")
outputdata = f.readlines()
fileExist = "true"
# ProxyServer finds a cache hit and generates a response message
tcpCliSock.send("HTTP/1.0 200 OK\r\n")
tcpCliSock.send("Content-Type:text/html\r\n")
for i in range(0, len(outputdata)):
tcpCliSock.send(outputdata[i])
print 'Read from cache'
# Error handling for file not found in cache
except IOError:
if fileExist == "false":
# Create a socket on the proxyserver
c = socket(AF_INET, SOCK_STREAM)
hostn = filename.replace("www.","",1)
print hostn
try:
# Connect to the socket to port 80
c.connect((hostn, 80))
# Create a temporary file on this socket and ask port 80 for the file requested by the client
fileobj = c.makefile('r', 0)
fileobj.write("GET "+"http://" + filename + " HTTP/1.0\n\n")
# Read the response into buffer
buff = fileobj.readlines()
# Create a new file in the cache for the requested file. Also send the response in the buffer to client socket and the corresponding file in the cache
tmpFile = open("./" + filename,"wb")
for line in buff:
tmpFile.write(line);
tcpCliSock.send(line);
except:
print "Illegal request"
else:
# HTTP response message for file not found
tcpCliSock.send("HTTP/1.0 404 sendErrorErrorError\r\n")
tcpCliSock.send("Content-Type:text/html\r\n")
tcpCliSock.send("\r\n")
# Close the client and the server sockets
tcpCliSock.close()
tcpSerSock.close()
But for every file I request I only get an "illegal request" message printed. There seems to be an issue that the proxy server actually is not able to retrieve the requested file by the client. Can someone tell me where I can improve the code.
This is the first time I am coding in Python so please mention any minor errors.
Your request is illegal. For normal http servers, GET must not contain a URL, but only the path. The rest of your proxy contains also many errors. You probably want to use sendall everywhere you use send. recv can receive less that one message, so you have to handle this case also.
Why do you use the strings "true" and "false" instead of True and False?
There is a security hole, as you can read any file on your computer through your proxy. Reading binary files won't work. You don't close opened files.
Inserting a .send to send an OK message apparently makes the rest of the code not work?
If I remove the client.send messages from the following code, it works. But with it, nothing happens in the browser, checking in Firefox, it says that the request went through, but there isn't any page displayed... it's just blank. Why would .send messages cause nothing to happen?
from socket import *
server = socket(AF_INET, SOCK_STREAM)
port = 12030
server.bind((gethostname(), port))
server.listen(1)
while True:
print 'Ready to serve'
conection, addr = server.accept()
try:
print 'Working'
message = conection.recv(1024)
conection.send("HTTP/1.0 200 OK\r\n")
conection.send("Content-Type:text/html\r\n")
filename = message.split()[1]
print "FILENAME", filename
f = open(filename[1:]) #cuts off the '/' in the request page
outputdata = f.read()
print "OUTDATA: ", outputdata
for i in range(0, len(outputdata)):
conection.send(outputdata[i])
conection.close()
except IOError:
print 'IO ERROR'
conection.send("404 NOT FOUND")
print message
conection.close()
except KeyboardInterrupt:
server.close()
conection.close()
break;
As seen here, it doesn't affect the data stream at all..
user ##$$ python webServer.py
Ready to serve
Working
FILENAME /HelloWorld.html
OUTDATA: <html>Hello World</html>
Ready to serve
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.