Both server and client are performing a receive operation and are therefore waiting for each other to send some data. Both processes are blocked.
The first thing to do is to remove the initial recv() in the client so that it can begin sending the contents of the file to the server.
Once that is fixed you will need to modify the way that the client is reading and sending the file. Currently the file is read once only, but you need to read the next chunk to send to the client in the while loop. You could rewrite it like this:
with open(file_name, 'rb') as f:
while(True):
l = f.read(1024)
if not l:
break
s.send(l)
Or you could use the "walrus" operator := to simplify reading the data and testing for end of file:
with open(file_name, 'rb') as f:
while l := f.read(1024):
s.send(l)
In addition to this the client must also provide a way for the server to determine when it has received all of the file. That can be done in two ways:
- The client sends the length of the message at the beginning so that the server can tell when it has received all of the message, or
- The client can append a sentinel character to the end of the message. The server looks out for this character and uses it to determine the end of message.
Here is the code to send a sentinel character after the message. The sentinel must not appear within the data; EOT (ASCII 0x04) should be safe:
with open(file_name, 'rb') as f:
while l := f.read(1024):
s.send(l)
s.send(b'\x04') # EOT sentinel character
Now looking at the server, this is incorrect:
get_file.data,file = get_file.conn.recv(1024)
because recv() returns a byte string, not a tuple. Change that to:
conn, addr = s.accept()
print('Connection from', addr)
data = conn.recv(1024)
Note that I have removed the get_file. prefix to the local variable names because there is no reason to bind these variables to the get_file function object. You should actually accept connections outside of this function and pass the connection object to the function. See below.
You will need to add a loop to the server to receive all of the data from the client. Similar to the client you can do this:
def get_file(conn):
with open('received_file.txt', 'wb') as f:
while data := conn.recv(1024):
if data[-1] == EOT:
f.write(data[:-1])
break
f.write(data)
Notice how this code checks for the existence of the sentinel EOT character to determine when the full message has been received.
And move:
print ('Server listening....')
conn, addr = s.accept()
print('Connection from', addr)
into the main body of your script.
Here are complete versions of your code with the above corrections:
server.py
import socket
port = 7142
s = socket.socket()
host = socket.gethostname()
s.bind((host, port))
s.listen(10)
EOT = ord(b'\x04')
def get_file(conn):
with open('received_file.txt', 'wb') as f:
while data := conn.recv(1024):
if data[-1] == EOT:
f.write(data[:-1])
break
f.write(data)
def compile_file():
try:
f = open('received_file.txt', 'r')
code_str = f.read()
code = compile(code_str, '', 'exec')
return(exec(code).decode())
except Exception as error:
return(error.decode())
print('Server listening....')
conn, addr = s.accept()
print('Connection from', addr)
get_file(conn)
compile_f = compile_file()
print("replying to client")
conn.send(compile_f)
print('done')
conn.close()
s.close()
client.py
import socket
import time
s = socket.socket()
host = socket.gethostname()
port = 7142
file_name = 'file.txt'
s.connect((host, port))
with open(file_name, 'rb') as f:
while l := f.read(1024):
s.send(l)
s.send(b'\x04') # EOT sentinel character
print("Sent request, waiting for reply...")
data = s.recv(1024)
print(repr(data))
time.sleep(10)
s.close()
f.close()
print('connection closed')
time.sleep(7)