Systems Programming & Concurrency
Exploration of low-level OS concepts including socket lifecycle management, process forking, and multi-threaded UI applications.
Project Overview
This collection of scripts demonstrates fundamental systems programming concepts. By interacting directly with OS-level APIs, I built robust networking tools and concurrent applications that manage shared resources and process states.
The project covers the implementing of a raw TCP server, managing the "Zombie Process" lifecycle through forking, and building a thread-safe real-time plotting application where the UI loop is decoupled from Input I/O.
Key Concepts Implemented
TCP Socket Lifecycle
Handled low-level socket operations (`bind`, `listen`, `accept`, `shutdown`) to create a robust Time Server that adheres to TCP protocols.
Process Forking
Demonstrated Unix process management by using `os.fork()` to spawn child processes, executing system commands (`ls -l`) concurrently with the parent.
Thread-Safe UI
Implemented a multi-threaded architecture where a daemon thread handles blocking user input while the main thread renders real-time animations, preventing UI freezes.
Source Code
1. TCP Time Server (`p7_hw6.py`)
A server that binds to a port and serves the current time to connected clients.
#!/usr/bin/env python3
#I am using code from server.py
import socket
import time
def bind_port(prt):
"""Create socket and bind to port prt.
"""
host = ''
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, prt))
s.listen(1)
return(s)
if __name__ == '__main__':
port = 55555
print('Time Server starting on port %d...' % port)
print('Press Ctrl+C to stop the server.')
thesocket = bind_port(port)
while True:
connection, peer = thesocket.accept()
current_time = time.ctime()
message = '\n\nCurrent time: %s\n\n' % current_time
outdata = message.encode('utf-8')
print('Sending time to %s...' % repr(peer), end='')
connection.sendall(outdata)
print('Done.')
connection.shutdown(socket.SHUT_RDWR)
connection.close()
2. Process Forking (`p4_b_hw8.py`)
Spawns a child process every 10 iterations to execute a system command.
#!/usr/bin/env python3
import os
import time
i = 1
while True:
print(i)
if i % 10 == 0:
print("About to fork...")
retval = os.fork()
if retval == 0:
print("Child process: About to execute ls -l")
os.execv('/bin/ls', ['ls', '-l'])
time.sleep(0.5)
i += 1
3. Threaded Real-Time Plotter (`p5_hw8.py`)
Updates a live graph based on user input without blocking the animation loop.
#!/usr/bin/env python3
# using logic from thread_example
import numpy as np
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import threading
import sys
current_val = 0.0
def get_input():
"""Continuously prompts user for input to update global variable."""
global current_val
print("Plot running. Enter numbers to update. The range of y-values visible in this graph is from -10 to 10 so keep that in mind.")
while True:
try:
current_val = float(input("New value: "))
except ValueError:
print("Input must be a number.", file=sys.stderr)
class Scope():
def __init__(self, ax, maxt=10, dt=0.02):
self.ax = ax
self.dt = dt
self.maxt = maxt
self.tdata = np.array([])
self.ydata = np.array([])
self.t0 = time.perf_counter()
self.line = Line2D(self.tdata, self.ydata)
self.ax.add_line(self.line)
self.ax.set_ylim(-10, 10)
self.ax.set_xlim(0, self.maxt)
def update(self, data):
t, y = data
self.tdata = np.append(self.tdata, t)
self.ydata = np.append(self.ydata, y)
self.ydata = self.ydata[self.tdata > (t - self.maxt)]
self.tdata = self.tdata[self.tdata > (t - self.maxt)]
self.line.set_data(self.tdata, self.ydata)
if len(self.tdata) > 0:
self.ax.set_xlim(self.tdata[0], self.tdata[0] + self.maxt)
self.ax.figure.canvas.draw()
return self.line,
def emitter(self):
while True:
t = time.perf_counter() - self.t0
yield t, current_val
if __name__ == '__main__':
input_thr = threading.Thread(target=get_input)
input_thr.daemon = True
input_thr.start()
dt = 0.01
fig, ax = plt.subplots()
scope = Scope(ax, maxt=10, dt=dt)
ani = animation.FuncAnimation(fig, scope.update, scope.emitter, interval=dt*1000., blit=True)
plt.show()