Systems Programming & Concurrency

Exploration of low-level OS concepts including socket lifecycle management, process forking, and multi-threaded UI applications. 소켓 라이프사이클, 프로세스 포킹, 멀티스레드 UI 등 저수준 OS 개념을 탐구합니다.

Python (Sockets) Multithreading Unix Process Forking Networking Protocols

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.이 스크립트 묶음은 시스템 프로그래밍의 기초 개념을 보여줍니다. OS 레벨 API를 직접 다루며, 공유 자원과 프로세스 상태를 관리하는 네트워크 도구/동시성 애플리케이션을 구현했습니다.

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.Raw TCP 서버 구현, 포킹을 통한 “좀비 프로세스” 라이프사이클 관리, 그리고 입력 I/O와 UI 루프를 분리한 스레드-세이프 실시간 플로팅 앱을 다룹니다.

Key Concepts Implemented구현한 핵심 개념

TCP Socket LifecycleTCP 소켓 라이프사이클

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스레드-세이프 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()