Reputation: 444
I have a TCP client-server where a client sends out shell commands to a server and the server responds with the output of said command. Some of the commands such as date or cd don't work because they are interactive I assume and my code doesn't handle it. Whenever I send said commands, my client seems to hang and just says sending... with my server never receiving anything.
I want to figure out how I can handle this with possibly a timeout where if it takes more than 5 seconds to send out a command, the client will cause a timeout or simply handle it and print an message saying the command did not execute successfully while keeping the client connected to the server.
Here is my code
Client:
import socket
# Client
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # creates TCP Socket
# local host and port
LOCAL_HOST = '127.0.0.1'
PORT = 5313
BUFFER_SIZE = 5000 # size of message
sock.settimeout(5)
# connect socket to ip and port
sock.connect((LOCAL_HOST, PORT))
print("Connected to server\n")
print("Enter quit to close connection\n")
while True:
message = input("Please enter a command:\n") # ask user to input message
if message == 'quit':
break
if len(message) == 0:
print("Please enter something")
message = input("Please enter a command:\n")
print("Sending %s" % message)
sock.send(str.encode(message)) # send message
command = str(sock.recv(BUFFER_SIZE), "utf-8") # receive message
print("received %s" % command)
print("closing connection with server")
sock.close()
Server:
import socket
import subprocess
# Server
# Some commands do not work such as cd. Date does not work on windows because it is interactive.
# creates TCP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
# port and server ip(localhost)
LOCAL_HOST = ''
PORT = 5313
BUFFER_SIZE = 5000 # size of message
# test connection
print("Server starting up on %s with port number %s" % (LOCAL_HOST, PORT))
# bind socket to ip and port
sock.bind((LOCAL_HOST, PORT))
# listen to socket
sock.listen(1)
# socket will accept connection and client address
print("Waiting for connection") # waiting for connection
connection, address = sock.accept() # accept connection with client address
print("Connected to", address) # connected by address
while True:
command = connection.recv(BUFFER_SIZE) # receive message from client
if not command:
break
if len(command) > 0:
terminal = subprocess.Popen(command[:].decode("utf-8"), shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
output = terminal.stdout.read() + terminal.stderr.read()
output_as_string = str(output, "utf-8")
connection.send(str.encode("0:") + str.encode(output_as_string))
print(output_as_string)
print("Closing Server")
sock.close()
connection.close()
Upvotes: 1
Views: 1426
Reputation: 73304
There are various ways to do it, but probably the easiest way is to call the subprocess.check_output() method, which allows you to specify a timeout value in seconds, and also returns the text that the child process generated, i.e.:
[...]
while True:
command = connection.recv(BUFFER_SIZE) # receive message from client
if not command:
break
command = command.decode("utf-8").strip()
if len(command) > 0:
try:
output_as_string = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True, timeout=5.0).decode("utf-8")
except subprocess.TimeoutExpired:
output_as_string = "Sub-process timed out!\r\n"
connection.send(str.encode("0:") + str.encode(output_as_string))
[...]
Upvotes: 1