Remote code running server seems not to be responding?

Viewed 46

I am working on a server that can run python code with socket but the code i have written seems not to be responding from the client or the server side i still can't figure that out when i run my server.py and connect to the server it seems that the server or the client just gives no output. I also get no errors just not working/giving an output.

Server.py:

import socket 

port = 7142
s = socket.socket()
host = socket.gethostname()
s.bind((host, port))
s.listen(10)

def get_file():
    print ('Server listening....')
    while True:
        get_file.conn, addr = s.accept()
        print('Connection from', addr)
        get_file.data,file = get_file.conn.recv(1024)
        
        
        with open('received_file.txt', 'wb') as f:
            if not get_file.data:
                get_file.conn.send(b'There is no data sent between servers')
            f.write(get_file.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())

get_file()
conn = get_file.conn
compile_f = compile_file()
conn.send(compile_f)
conn.close()

Client.py

import socket
import time


s = socket.socket()
host = socket.gethostname()
port = 7142
file_name = 'file.txt'

s.connect((host, port))

data = s.recv(1024)
f = open(file_name,'rb')
l = f.read(1024)

while(l):
    s.send(l)
    break


print(repr(data))
time.sleep(10)
s.close()
f.close()
print('connection closed')
time.sleep(7)
1 Answers

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)
Related