The subprocess module enables the execution of system termianl commands from within Python code and captures their output.
import subprocess
command = input('Enter a terminal command:')
process = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
output = process.stdout.read() + process.stderr.read()
print(output.decode('gbk'))
Network Commend Execution Example
Server
import subprocess
import socket
sock = socket.socket()
sock.bind(('127.0.0.1', 8080))
sock.listen()
conn, addr = sock.accept()
while True:
command = conn.recv(1024).decode('utf-8')
proc = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
result = proc.stdout.read() + proc.stderr.read()
conn.send(result)
Client
import socket
client_socket = socket.socket()
client_socket.connect(('127.0.0.1', 8080))
while True:
cmd = input('Input command:')
client_socket.send(cmd.encode('utf-8'))
response = client_socket.recv(1024).decode('gbk')
print(response)
TCP Packet Sticking (TCP Nagle Algorithm)
In TCP's streaming protocol, multiple small data packets sent in rapid succession may be combined into a single transmission, causing the receiver to recieve concatenated data.
Server
import socket
serv = socket.socket()
serv.bind(('127.0.0.1', 9090))
serv.listen()
connection, client_addr = serv.accept()
packet1 = connection.recv(1024).decode('utf-8')
packet2 = connection.recv(1024).decode('utf-8')
packet3 = connection.recv(1024).decode('utf-8')
print(f'Packet1:{packet1}, Packet2:{packet2}, Packet3:{packet3}')
Client
import socket
import time
cl = socket.socket()
cl.connect(('127.0.0.1', 9090))
cl.send(b'msg1')
time.sleep(0.5)
cl.send(b'msg2')
time.sleep(0.5)
cl.send(b'msg3')
Using struct for Header-Based Packet Separation
import struct
sample_data = 'example payload'
# Pack an integer into 4 bytes
header = struct.pack('i', 1500)
print(header, len(header))
# Unpack to retrieve the integer
original_length = struct.unpack('i', header)[0]
print(original_length)
Server with struct header
import subprocess
import socket
import struct
server_sock = socket.socket()
server_sock.bind(('127.0.0.1', 7070))
server_sock.listen()
conn, addr = server_sock.accept()
while True:
cmd = conn.recv(1024).decode('utf-8')
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
cmd_result = proc.stdout.read() + proc.stderr.read()
result_header = struct.pack('i', len(cmd_result))
conn.send(result_header)
conn.send(cmd_result)
Client with struct header
import socket
import struct
cl_sock = socket.socket()
cl_sock.connect(('127.0.0.1', 7070))
while True:
user_cmd = input('Command:')
cl_sock.send(user_cmd.encode('utf-8'))
received_header = cl_sock.recv(4)
data_size = struct.unpack('i', received_header)[0]
actual_data = cl_sock.recv(data_size)
print(actual_data.decode('gbk'))
Enhanced Header with JSON Metadata
Server
import json
import socket
import struct
s = socket.socket()
s.bind(('127.0.0.1', 6060))
s.listen()
conn, addr = s.accept()
header_bytes = conn.recv(4)
meta_length = struct.unpack('i', header_bytes)[0]
json_bytes = conn.recv(meta_length)
metadata = json.loads(json_bytes.decode('utf-8'))
print(metadata)
Client
import json
import socket
import struct
c = socket.socket()
c.connect(('127.0.0.1', 6060))
file_info = {
'filename': 'sample_video.mp4',
'filesize': 50000000
}
json_str = json.dumps(file_info)
json_data = json_str.encode('utf-8')
header = struct.pack('i', len(json_data))
c.send(header)
c.send(json_data)
Large File Upload over TCP
Server
import socket
import struct
import json
serv = socket.socket()
serv.bind(('127.0.0.1', 5050))
serv.listen()
while True:
conn, addr = serv.accept()
try:
while True:
header = conn.recv(4)
dict_len = struct.unpack('i', header)[0]
json_dict = conn.recv(dict_len).decode('utf-8')
info = json.loads(json_dict)
fname = info.get('filename')
fsize = info.get('filesize')
with open(fname, 'wb') as f:
remaining = fsize
while remaining > 0:
chunk = conn.recv(min(1024, remaining))
f.write(chunk)
remaining -= len(chunk)
print(f'File {fname} received.')
except Exception as err:
print(f'Error: {err}')
Client
import socket
import struct
import json
import os
client = socket.socket()
client.connect(('127.0.0.1', 5050))
filepath = '/path/to/large_file.dat'
while True:
input('Press Enter to upload:')
with open(filepath, 'rb') as f:
file_content = f.read()
metadata = {
'filename': os.path.basename(filepath),
'filesize': len(file_content)
}
json_metadata = json.dumps(metadata)
meta_bytes = json_metadata.encode('utf-8')
meta_header = struct.pack('i', len(meta_bytes))
client.send(meta_header)
client.send(meta_bytes)
with open(filepath, 'rb') as f:
while chunk := f.read(1024):
client.send(chunk)
print(f'Uploaded {metadata["filename"]}')
UDP Protocol Basics
UDP is a connectionless datagram protocol without built-in reliability or ordering guarantees.
Server
import socket
udp_server = socket.socket(type=socket.SOCK_DGRAM)
udp_server.bind(('127.0.0.1', 9999))
msg1, addr1 = udp_server.recvfrom(1024)
msg2, addr2 = udp_server.recvfrom(1024)
msg3, addr3 = udp_server.recvfrom(1024)
print(f'{addr1}: {msg1}, {addr2}: {msg2}, {addr3}: {msg3}')
Client
import socket
udp_client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 9999)
udp_client.sendto(b'packet1', server_addr)
udp_client.sendto(b'packet2', server_addr)
udp_client.sendto(b'packet3', server_addr)
Simple UDP Chat Room
Server
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8888))
client_addresses = []
while True:
data, addr = server.recvfrom(1024)
if addr not in client_addresses:
client_addresses.append(addr)
print(f'{addr}: {data.decode()}')
reply = input('Reply to all: ')
for client in client_addresses:
server.sendto(reply.encode(), client)
if reply.lower() == 'quit':
break
Client
import socket
import threading
client = socket.socket(type=socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 8888)
# Receive messages in a separate thread
def receive_messages():
while True:
data, _ = client.recvfrom(1024)
print(f'Server: {data.decode()}')
receiver = threading.Thread(target=receive_messages, daemon=True)
receiver.start()
while True:
message = input('Your message: ')
client.sendto(message.encode(), server_address)
Socketserver Module for Simplified Servers
The socketserver module provides higher-level abstractions for creating network servers.
TCPServer Example
import socketserver
class CustomTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
print(f'Connected: {self.client_address}')
try:
while True:
received = self.request.recv(1024).decode('utf-8')
if not received:
break
response = received.upper()
self.request.send(response.encode('utf-8'))
except ConnectionError as e:
print(f'Connection lost: {e}')
if __name__ == '__main__':
with socketserver.ThreadingTCPServer(('127.0.0.1', 8080), CustomTCPHandler) as server:
server.serve_forever()
UDPServer Example
import socketserver
class CustomUDPHandler(socketserver.BaseRequestHandler):
def handle(self):
data, socket = self.request
print(f'Received from {self.client_address}: {data.decode()}')
socket.sendto(data.upper(), self.client_address)
if __name__ == '__main__':
with socketserver.ThreadingUDPServer(('127.0.0.1', 9999), CustomUDPHandler) as server:
server.serve_forever()