Introducción
Este tutorial exhaustivo te guiará a través del uso de la biblioteca ctypes de Python para interactuar con la API de Windows. Aprenderás a acceder a la funcionalidad del sistema Windows, gestionar procesos y aprovechar las características específicas de Windows directamente desde Python. Al final de este laboratorio, comprenderás cómo construir aplicaciones que pueden integrarse perfectamente con el sistema operativo Windows y realizar operaciones potentes a nivel de sistema.
Comprender la biblioteca ctypes de Python
En este paso, exploraremos los conceptos básicos de la biblioteca ctypes de Python, que sirve como base para interactuar con la API de Windows. La biblioteca ctypes actúa como un puente entre Python y las bibliotecas nativas de C, permitiéndonos llamar a funciones directamente desde DLLs (Dynamic Link Libraries - Bibliotecas de Enlace Dinámico).
¿Qué es ctypes?
ctypes es una biblioteca de funciones externas para Python que proporciona tipos de datos compatibles con C y permite llamar a funciones en DLLs o bibliotecas compartidas. Es particularmente útil para:
- Acceder a funciones del sistema de bajo nivel
- Interactuar con hardware
- Llamar a funciones desde bibliotecas específicas de la plataforma
Instalación de los paquetes requeridos
Antes de empezar a escribir código, instalemos los paquetes necesarios. Abre una terminal en el WebIDE y ejecuta:
pip install pywin32-ctypes
Esto instalará una biblioteca compatible que funciona con nuestro entorno.
Uso básico de ctypes
Creemos un script de Python simple para entender cómo funciona ctypes. En el WebIDE, crea un nuevo archivo llamado ctypes_basics.py en el directorio /home/labex/project con el siguiente contenido:
import ctypes
## Load a standard C library
libc = ctypes.CDLL('libc.so.6')
## Call a simple C function
print("Random number from C library:", libc.rand())
## Find out the size of int type on this machine
print("Size of int:", ctypes.sizeof(ctypes.c_int), "bytes")
## Create and use a C-compatible string
message = ctypes.create_string_buffer(b"Hello from ctypes!")
print("C-compatible string:", message.value.decode())
print("String buffer size:", ctypes.sizeof(message), "bytes")
Ejecuta el script usando:
python3 ctypes_basics.py
Deberías ver una salida similar a esta:
Random number from C library: 1804289383
Size of int: 4 bytes
C-compatible string: Hello from ctypes!
String buffer size: 19 bytes
Comprensión de los tipos de datos C en Python
ctypes proporciona envoltorios compatibles con Python para los tipos de datos C. Aquí hay una tabla de referencia de los tipos de datos C comunes y sus equivalentes ctypes:
| Tipo C | Tipo ctypes | Tipo Python |
|---|---|---|
| char | c_char | Objeto bytes de 1 carácter |
| int | c_int | int |
| unsigned int | c_uint | int |
| long | c_long | int |
| void * | c_void_p | int o None |
| char * | c_char_p | bytes o None |
| wchar_t * | c_wchar_p | str o None |
Exploremos estos tipos de datos con otro ejemplo. Crea un archivo llamado ctypes_types.py:
import ctypes
## Integer types
i = ctypes.c_int(42)
ui = ctypes.c_uint(123)
print(f"Integer: {i.value}, Unsigned Integer: {ui.value}")
## Floating point types
f = ctypes.c_float(3.14)
d = ctypes.c_double(2.71828)
print(f"Float: {f.value}, Double: {d.value}")
## Character and string types
c = ctypes.c_char(b'A')
s = ctypes.c_char_p(b"Hello, World!")
print(f"Character: {c.value.decode()}, String: {s.value.decode()}")
## Create an array of integers
int_array = (ctypes.c_int * 5)(1, 2, 3, 4, 5)
print("Array elements:", [int_array[i] for i in range(5)])
Ejecuta el script:
python3 ctypes_types.py
Salida esperada:
Integer: 42, Unsigned Integer: 123
Float: 3.140000104904175, Double: 2.71828
Character: A, String: Hello, World!
Array elements: [1, 2, 3, 4, 5]
Esta comprensión fundamental de ctypes nos ayudará a medida que avancemos para interactuar con bibliotecas de sistema más complejas y, específicamente, con la API de Windows.
Acceso a bibliotecas del sistema con ctypes
En este paso, aprenderemos a acceder a las bibliotecas del sistema y a llamar a sus funciones utilizando ctypes. Dado que estamos trabajando en un entorno Linux, nos centraremos en las bibliotecas del sistema Linux, al tiempo que explicamos los principios que también se aplican al acceso a la API de Windows.
Carga de bibliotecas dinámicas
En Python, podemos cargar bibliotecas dinámicas utilizando varios métodos proporcionados por ctypes:
CDLL- para cargar bibliotecas C estándarWinDLL- para cargar DLLs de Windows (cuando se está en Windows)OleDLL- para cargar bibliotecas COM (cuando se está en Windows)
Creemos un archivo llamado system_info.py para explorar la información del sistema utilizando bibliotecas estándar:
import ctypes
import os
import platform
print(f"Python Platform: {platform.platform()}")
print(f"System: {platform.system()}")
print(f"Machine: {platform.machine()}")
print(f"Processor: {platform.processor()}")
## Load the C standard library
libc = ctypes.CDLL('libc.so.6')
## Get system information
print("\n--- System Information ---")
## Get hostname
hostname_buffer = ctypes.create_string_buffer(1024)
if libc.gethostname(hostname_buffer, ctypes.sizeof(hostname_buffer)) == 0:
print(f"Hostname: {hostname_buffer.value.decode()}")
else:
print("Failed to get hostname")
## Get user information
uid = os.getuid()
pwd = libc.getpwuid(uid)
if pwd:
print(f"Current user ID: {uid}")
else:
print(f"Current user ID: {uid} (failed to get user info)")
## Memory page size
page_size = libc.getpagesize()
print(f"Memory page size: {page_size} bytes")
## Get system uptime (if available)
try:
class timespec(ctypes.Structure):
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
time_buf = timespec()
CLOCK_BOOTTIME = 7 ## Linux specific
if hasattr(libc, 'clock_gettime') and libc.clock_gettime(CLOCK_BOOTTIME, ctypes.byref(time_buf)) == 0:
uptime_seconds = time_buf.tv_sec
days, remainder = divmod(uptime_seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
print(f"System uptime: {days} days, {hours} hours, {minutes} minutes, {seconds} seconds")
else:
print("Could not get system uptime")
except Exception as e:
print(f"Error getting uptime: {e}")
Ejecuta el script:
python3 system_info.py
Deberías ver información detallada sobre tu sistema, similar a esto:
Python Platform: Linux-5.15.0-1031-aws-x86_64-with-glibc2.35
System: Linux
Machine: x86_64
Processor: x86_64
--- System Information ---
Hostname: labex-container
Current user ID: 1000
Memory page size: 4096 bytes
System uptime: 0 days, 1 hours, 23 minutes, 45 seconds
Creación de un monitor de procesos
Ahora, creemos una aplicación más práctica: un monitor de procesos simple que mostrará los procesos en ejecución. Crea un archivo llamado process_monitor.py:
import ctypes
import os
import time
from datetime import datetime
def list_processes():
"""List all running processes using /proc filesystem"""
processes = []
## On Linux, process information is available in the /proc filesystem
for pid in os.listdir('/proc'):
if pid.isdigit():
try:
## Read process name from /proc/[pid]/comm
with open(f'/proc/{pid}/comm', 'r') as f:
name = f.read().strip()
## Get process status
with open(f'/proc/{pid}/status', 'r') as f:
status_lines = f.readlines()
status = {}
for line in status_lines:
if ':' in line:
key, value = line.split(':', 1)
status[key.strip()] = value.strip()
## Get memory usage (VmRSS is physical memory used)
memory_kb = int(status.get('VmRSS', '0 kB').split()[0]) if 'VmRSS' in status else 0
processes.append({
'pid': int(pid),
'name': name,
'state': status.get('State', 'Unknown'),
'memory_kb': memory_kb
})
except (IOError, FileNotFoundError, ProcessLookupError):
## Process might have terminated while we were reading
continue
return processes
def display_processes(processes, top_n=10):
"""Display processes sorted by memory usage"""
## Sort processes by memory usage (highest first)
sorted_processes = sorted(processes, key=lambda p: p['memory_kb'], reverse=True)
## Display only top N processes
print(f"\nTop {top_n} processes by memory usage at {datetime.now().strftime('%H:%M:%S')}:")
print(f"{'PID':<7} {'NAME':<20} {'STATE':<10} {'MEMORY (KB)':<12}")
print("-" * 50)
for proc in sorted_processes[:top_n]:
print(f"{proc['pid']:<7} {proc['name'][:19]:<20} {proc['state']:<10} {proc['memory_kb']:<12}")
## Monitor processes continuously
print("Simple Process Monitor")
print("Press Ctrl+C to exit")
try:
while True:
processes = list_processes()
display_processes(processes)
time.sleep(3) ## Update every 3 seconds
except KeyboardInterrupt:
print("\nProcess monitoring stopped")
Ejecuta el monitor de procesos:
python3 process_monitor.py
Deberías ver una salida similar a esta, que se actualizará cada 3 segundos:
Simple Process Monitor
Press Ctrl+C to exit
Top 10 processes by memory usage at 14:30:25:
PID NAME STATE MEMORY (KB)
-------------------------------------------------------
1234 python3 S (sleeping) 56789
2345 node S (sleeping) 34567
3456 code S (sleeping) 23456
...
Deja que el monitor de procesos se ejecute durante unos 10 segundos, luego presiona Ctrl+C para detenerlo.
En estos ejemplos, hemos aprendido a:
- Cargar y usar bibliotecas del sistema con
ctypes - Acceder a la información del sistema
- Crear una herramienta práctica de monitoreo de procesos
Estos principios son los mismos que usarías para interactuar con la API de Windows a través de ctypes, solo con diferentes nombres de bibliotecas y llamadas a funciones.
Creación y uso de estructuras C con ctypes
En este paso, aprenderemos a definir y usar estructuras C en Python. Las estructuras son esenciales cuando se trabaja con APIs del sistema, ya que se utilizan comúnmente para intercambiar datos entre Python y las bibliotecas del sistema.
Comprensión de las estructuras C en Python
Las estructuras C se pueden representar en Python utilizando la clase ctypes.Structure. Esto nos permite crear estructuras de datos complejas que coinciden con el diseño de memoria esperado por las funciones C.
Creemos un archivo llamado struct_example.py para explorar cómo trabajar con estructuras:
import ctypes
## Define a simple C structure
class Point(ctypes.Structure):
_fields_ = [
("x", ctypes.c_int),
("y", ctypes.c_int)
]
## Create an instance of the Point structure
p = Point(10, 20)
print(f"Point coordinates: ({p.x}, {p.y})")
## Modify structure fields
p.x = 100
p.y = 200
print(f"Updated coordinates: ({p.x}, {p.y})")
## Create a Point from a dictionary
values = {"x": 30, "y": 40}
p2 = Point(**values)
print(f"Point from dictionary: ({p2.x}, {p2.y})")
## Get the raw memory view (pointer) of the structure
p_ptr = ctypes.pointer(p)
print(f"Memory address of p: {ctypes.addressof(p)}")
print(f"Access via pointer: ({p_ptr.contents.x}, {p_ptr.contents.y})")
## Define a nested structure
class Rectangle(ctypes.Structure):
_fields_ = [
("top_left", Point),
("bottom_right", Point),
("color", ctypes.c_int)
]
## Create a rectangle with two points
rect = Rectangle(Point(0, 0), Point(100, 100), 0xFF0000)
print(f"Rectangle: Top-Left: ({rect.top_left.x}, {rect.top_left.y}), "
f"Bottom-Right: ({rect.bottom_right.x}, {rect.bottom_right.y}), "
f"Color: {hex(rect.color)}")
## Calculate the area (demonstrating structure manipulation)
width = rect.bottom_right.x - rect.top_left.x
height = rect.bottom_right.y - rect.top_left.y
print(f"Rectangle area: {width * height}")
Ejecuta el script:
python3 struct_example.py
Deberías ver una salida similar a esta:
Point coordinates: (10, 20)
Updated coordinates: (100, 200)
Point from dictionary: (30, 40)
Memory address of p: 140737345462208
Access via pointer: (100, 200)
Rectangle: Top-Left: (0, 0), Bottom-Right: (100, 100), Color: 0xff0000
Rectangle area: 10000
Creación de una utilidad de tiempo del sistema
Ahora, creemos una aplicación práctica que utiliza estructuras C para interactuar con las funciones de tiempo del sistema. Crea un archivo llamado time_utility.py:
import ctypes
import time
from datetime import datetime
## Define the timespec structure (used in Linux for high-resolution time)
class timespec(ctypes.Structure):
_fields_ = [
("tv_sec", ctypes.c_long),
("tv_nsec", ctypes.c_long)
]
## Define the tm structure (used for calendar time representation)
class tm(ctypes.Structure):
_fields_ = [
("tm_sec", ctypes.c_int), ## seconds (0 - 60)
("tm_min", ctypes.c_int), ## minutes (0 - 59)
("tm_hour", ctypes.c_int), ## hours (0 - 23)
("tm_mday", ctypes.c_int), ## day of month (1 - 31)
("tm_mon", ctypes.c_int), ## month of year (0 - 11)
("tm_year", ctypes.c_int), ## year - 1900
("tm_wday", ctypes.c_int), ## day of week (0 - 6, Sunday = 0)
("tm_yday", ctypes.c_int), ## day of year (0 - 365)
("tm_isdst", ctypes.c_int) ## is daylight saving time in effect
]
## Load the C library
libc = ctypes.CDLL("libc.so.6")
def get_system_time():
"""Get the current system time using C functions"""
## Get current time as seconds since epoch
time_t_ptr = ctypes.pointer(ctypes.c_long())
libc.time(time_t_ptr) ## time() function gets current time
## Convert to printable time string
time_val = time_t_ptr.contents.value
time_str = ctypes.string_at(libc.ctime(time_t_ptr))
return {
"timestamp": time_val,
"formatted_time": time_str.decode().strip()
}
def get_high_resolution_time():
"""Get high resolution time using clock_gettime"""
ts = timespec()
## CLOCK_REALTIME is usually 0
CLOCK_REALTIME = 0
## Call clock_gettime to fill the timespec structure
if libc.clock_gettime(CLOCK_REALTIME, ctypes.byref(ts)) != 0:
raise OSError("Failed to get time")
return {
"seconds": ts.tv_sec,
"nanoseconds": ts.tv_nsec,
"precise_time": ts.tv_sec + (ts.tv_nsec / 1_000_000_000)
}
def time_breakdown():
"""Break down the current time into its components using localtime"""
## Get current time
time_t_ptr = ctypes.pointer(ctypes.c_long())
libc.time(time_t_ptr)
## Get local time
tm_ptr = libc.localtime(time_t_ptr)
tm_struct = ctypes.cast(tm_ptr, ctypes.POINTER(tm)).contents
## Return time components
return {
"year": 1900 + tm_struct.tm_year,
"month": 1 + tm_struct.tm_mon, ## tm_mon is 0-11, we adjust to 1-12
"day": tm_struct.tm_mday,
"hour": tm_struct.tm_hour,
"minute": tm_struct.tm_min,
"second": tm_struct.tm_sec,
"weekday": tm_struct.tm_wday, ## 0 is Sunday
"yearday": tm_struct.tm_yday + 1 ## tm_yday is 0-365, we adjust to 1-366
}
## Main program
print("Time Utility using C Structures")
print("-" * 40)
## Get and display system time
sys_time = get_system_time()
print(f"System time: {sys_time['formatted_time']}")
print(f"Timestamp (seconds since epoch): {sys_time['timestamp']}")
## Get and display high-resolution time
hi_res = get_high_resolution_time()
print(f"\nHigh resolution time:")
print(f"Seconds: {hi_res['seconds']}")
print(f"Nanoseconds: {hi_res['nanoseconds']}")
print(f"Precise time: {hi_res['precise_time']}")
## Get and display time breakdown
components = time_breakdown()
print(f"\nTime breakdown:")
print(f"Date: {components['year']}-{components['month']:02d}-{components['day']:02d}")
print(f"Time: {components['hour']:02d}:{components['minute']:02d}:{components['second']:02d}")
print(f"Day of week: {components['weekday']} (0=Sunday)")
print(f"Day of year: {components['yearday']}")
## Compare with Python's datetime
now = datetime.now()
print(f"\nPython datetime: {now}")
print(f"Python timestamp: {time.time()}")
Ejecuta la utilidad de tiempo:
python3 time_utility.py
Deberías ver una salida similar a esta:
Time Utility using C Structures
----------------------------------------
System time: Wed Jun 14 15:22:36 2023
Timestamp (seconds since epoch): 1686756156
High resolution time:
Seconds: 1686756156
Nanoseconds: 923456789
Precise time: 1686756156.923457
Time breakdown:
Date: 2023-06-14
Time: 15:22:36
Day of week: 3 (0=Sunday)
Day of year: 165
Python datetime: 2023-06-14 15:22:36.923499
Python timestamp: 1686756156.9234989
Comprensión de la gestión de memoria con ctypes
Cuando se trabaja con ctypes y estructuras C, es importante comprender la gestión de la memoria. Creemos un ejemplo más, memory_management.py, para demostrar esto:
import ctypes
import gc ## Garbage collector module
## Define a simple structure
class MyStruct(ctypes.Structure):
_fields_ = [
("id", ctypes.c_int),
("value", ctypes.c_double),
("name", ctypes.c_char * 32) ## Fixed-size character array
]
def demonstrate_memory_management():
print("Memory Management with ctypes")
print("-" * 40)
## Create a structure instance
my_data = MyStruct(
id=1,
value=3.14159,
name=b"Example"
)
print(f"Structure size: {ctypes.sizeof(my_data)} bytes")
print(f"Memory address: {hex(ctypes.addressof(my_data))}")
## Create a pointer to the structure
data_ptr = ctypes.pointer(my_data)
print(f"Pointer value: {hex(ctypes.cast(data_ptr, ctypes.c_void_p).value)}")
## Access through pointer
print(f"Access via pointer: id={data_ptr.contents.id}, value={data_ptr.contents.value}")
## Allocate memory for a new structure
new_struct_ptr = ctypes.POINTER(MyStruct)()
new_struct_ptr = ctypes.cast(
ctypes.create_string_buffer(ctypes.sizeof(MyStruct)),
ctypes.POINTER(MyStruct)
)
## Initialize the allocated memory
new_struct = new_struct_ptr.contents
new_struct.id = 2
new_struct.value = 2.71828
new_struct.name = b"Allocated"
print(f"\nAllocated structure memory address: {hex(ctypes.addressof(new_struct))}")
print(f"Allocated structure content: id={new_struct.id}, value={new_struct.value}, name={new_struct.name.decode()}")
## Create an array of structures
StructArray = MyStruct * 3
struct_array = StructArray(
MyStruct(10, 1.1, b"First"),
MyStruct(20, 2.2, b"Second"),
MyStruct(30, 3.3, b"Third")
)
print("\nArray of structures:")
for i, item in enumerate(struct_array):
print(f" [{i}] id={item.id}, value={item.value}, name={item.name.decode()}")
## Force garbage collection
print("\nForcing garbage collection...")
gc.collect()
## Memory is automatically managed by Python
## Run the demonstration
demonstrate_memory_management()
Ejecuta el script de gestión de memoria:
python3 memory_management.py
Deberías ver una salida similar a esta:
Memory Management with ctypes
----------------------------------------
Structure size: 48 bytes
Memory address: 0x7f3c2e32b040
Pointer value: 0x7f3c2e32b040
Access via pointer: id=1, value=3.14159
Allocated structure memory address: 0x7f3c2e32b0a0
Allocated structure content: id=2, value=2.71828, name=Allocated
Array of structures:
[0] id=10, value=1.1, name=First
[1] id=20, value=2.2, name=Second
[2] id=30, value=3.3, name=Third
Forcing garbage collection...
En estos ejemplos, hemos aprendido a:
- Definir y usar estructuras C en Python con
ctypes - Crear punteros a estructuras y acceder a su contenido
- Crear estructuras anidadas y matrices de estructuras
- Construir aplicaciones prácticas utilizando funciones de tiempo del sistema
- Gestionar la memoria cuando se trabaja con
ctypes
Estas habilidades son esenciales cuando se trabaja con funciones de la API de Windows, que con frecuencia requieren estructuras de datos complejas para pasar información de un lado a otro.
Creación de una aplicación completa de monitor del sistema
En este paso final, reuniremos todos nuestros conocimientos para construir una aplicación completa de monitor del sistema. Esta aplicación utilizará ctypes para recopilar información del sistema, mostrar métricas en tiempo real y demostrar cómo estructurar una aplicación Python más grande que interactúa con las bibliotecas del sistema.
Creación del monitor del sistema
Crea un nuevo archivo llamado system_monitor.py con el siguiente contenido:
import ctypes
import os
import time
import platform
from datetime import datetime
class SystemMonitor:
"""Aplicación de monitoreo del sistema usando ctypes"""
def __init__(self):
"""Inicializa el monitor del sistema"""
self.libc = ctypes.CDLL("libc.so.6")
self.running = False
## Define a timespec structure for time-related functions
class timespec(ctypes.Structure):
_fields_ = [
("tv_sec", ctypes.c_long),
("tv_nsec", ctypes.c_long)
]
self.timespec = timespec
## Print basic system information
print(f"System Monitor for {platform.system()} {platform.release()}")
print(f"Python Version: {platform.python_version()}")
print(f"Machine: {platform.machine()}")
print("-" * 50)
def get_uptime(self):
"""Get system uptime information"""
try:
CLOCK_BOOTTIME = 7 ## Linux specific
time_buf = self.timespec()
if hasattr(self.libc, 'clock_gettime') and self.libc.clock_gettime(CLOCK_BOOTTIME, ctypes.byref(time_buf)) == 0:
uptime_seconds = time_buf.tv_sec
days, remainder = divmod(uptime_seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
return {
"total_seconds": uptime_seconds,
"days": days,
"hours": hours,
"minutes": minutes,
"seconds": seconds
}
return None
except Exception as e:
print(f"Error getting uptime: {e}")
return None
def get_memory_info(self):
"""Get memory usage information using /proc/meminfo"""
memory_info = {}
try:
with open('/proc/meminfo', 'r') as f:
for line in f:
if ':' in line:
key, value = line.split(':', 1)
## Remove 'kB' and convert to integer
value = value.strip()
if 'kB' in value:
value = int(value.split()[0]) * 1024 ## Convert to bytes
memory_info[key.strip()] = value
## Calculate memory usage percentage
if 'MemTotal' in memory_info and 'MemAvailable' in memory_info:
total = int(memory_info['MemTotal'])
available = int(memory_info['MemAvailable'])
used = total - available
memory_info['UsedPercentage'] = (used / total) * 100
return memory_info
except Exception as e:
print(f"Error getting memory info: {e}")
return {}
def get_cpu_info(self):
"""Get CPU information using /proc/stat"""
cpu_info = {'cpu_percent': 0}
try:
## We need two readings to calculate CPU usage
def get_cpu_sample():
with open('/proc/stat', 'r') as f:
line = f.readline()
cpu_values = [int(x) for x in line.split()[1:8]]
return sum(cpu_values), cpu_values[3] ## Return total and idle
## First sample
total1, idle1 = get_cpu_sample()
time.sleep(0.5) ## Wait for 0.5 second
## Second sample
total2, idle2 = get_cpu_sample()
## Calculate CPU usage
total_delta = total2 - total1
idle_delta = idle2 - idle1
if total_delta > 0:
cpu_info['cpu_percent'] = 100 * (1 - idle_delta / total_delta)
return cpu_info
except Exception as e:
print(f"Error getting CPU info: {e}")
return cpu_info
def get_disk_info(self):
"""Get disk usage information"""
try:
## Get disk usage for the root filesystem
stat = os.statvfs('/')
## Calculate total, free, and used space
total = stat.f_blocks * stat.f_frsize
free = stat.f_bfree * stat.f_frsize
used = total - free
return {
'total_bytes': total,
'free_bytes': free,
'used_bytes': used,
'used_percent': (used / total) * 100 if total > 0 else 0
}
except Exception as e:
print(f"Error getting disk info: {e}")
return {}
def get_process_count(self):
"""Count running processes"""
try:
return len([p for p in os.listdir('/proc') if p.isdigit()])
except Exception as e:
print(f"Error counting processes: {e}")
return 0
def format_bytes(self, bytes_value):
"""Format bytes into a human-readable format"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_value < 1024 or unit == 'TB':
return f"{bytes_value:.2f} {unit}"
bytes_value /= 1024
def display_dashboard(self):
"""Display the system monitoring dashboard"""
## Clear the screen (works in most terminals)
print("\033c", end="")
## Display header
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"System Monitor - {current_time}")
print("-" * 50)
## Display uptime
uptime = self.get_uptime()
if uptime:
print(f"Uptime: {uptime['days']} days, {uptime['hours']} hours, "
f"{uptime['minutes']} minutes, {uptime['seconds']} seconds")
## Display CPU usage
cpu_info = self.get_cpu_info()
print(f"CPU Usage: {cpu_info['cpu_percent']:.1f}%")
## Display memory information
memory_info = self.get_memory_info()
if memory_info and 'MemTotal' in memory_info:
print("\nMemory Information:")
total = int(memory_info['MemTotal'])
available = int(memory_info.get('MemAvailable', 0))
used = total - available
print(f" Total: {self.format_bytes(total)}")
print(f" Used: {self.format_bytes(used)} ({memory_info.get('UsedPercentage', 0):.1f}%)")
print(f" Available: {self.format_bytes(available)}")
if 'SwapTotal' in memory_info:
swap_total = int(memory_info['SwapTotal'])
swap_free = int(memory_info.get('SwapFree', 0))
swap_used = swap_total - swap_free
if swap_total > 0:
print(f" Swap Used: {self.format_bytes(swap_used)} "
f"({(swap_used / swap_total) * 100:.1f}%)")
## Display disk information
disk_info = self.get_disk_info()
if disk_info:
print("\nDisk Information (/):")
print(f" Total: {self.format_bytes(disk_info['total_bytes'])}")
print(f" Used: {self.format_bytes(disk_info['used_bytes'])} "
f"({disk_info['used_percent']:.1f}%)")
print(f" Free: {self.format_bytes(disk_info['free_bytes'])}")
## Display process count
process_count = self.get_process_count()
print(f"\nRunning Processes: {process_count}")
print("\nPress Ctrl+C to exit")
def start_monitoring(self, interval=2):
"""Start the system monitoring with the specified refresh interval"""
self.running = True
try:
while self.running:
self.display_dashboard()
time.sleep(interval)
except KeyboardInterrupt:
print("\nMonitoring stopped.")
self.running = False
## Create and start the system monitor
if __name__ == "__main__":
monitor = SystemMonitor()
monitor.start_monitoring()
Ejecuta el monitor del sistema:
python3 system_monitor.py
El monitor del sistema mostrará información en tiempo real sobre tu sistema, actualizándose cada 2 segundos. Deberías ver un panel con:
- Tiempo de actividad del sistema (Uptime)
- Uso de la CPU
- Información de la memoria (total, usada, disponible)
- Uso del disco
- Recuento de procesos
Deja que el monitor se ejecute durante unos momentos para observar cómo cambian las métricas, luego presiona Ctrl+C para salir.
Comprensión de la estructura del monitor del sistema
Desglosemos los componentes clave de nuestro monitor del sistema:
- Estructura de la clase: Uso de la programación orientada a objetos para organizar nuestro código
- Organización de métodos: Separación de la funcionalidad en métodos distintos
- Manejo de errores: Uso de bloques try-except para manejar posibles errores
- Formateo de datos: Conversión de datos sin procesar a formatos legibles por humanos
- Actualizaciones en tiempo real: Uso de un bucle con time.sleep() para actualizaciones periódicas
Agregar documentación
Ahora, agreguemos un archivo de documentación para nuestro monitor del sistema. Crea un archivo llamado README.md:
Monitor del sistema Python
Una aplicación completa de monitoreo del sistema construida con Python utilizando ctypes para las interacciones del sistema.
Características
- Monitoreo del uso de la CPU en tiempo real
- Seguimiento del uso de la memoria
- Análisis del espacio en disco
- Recuento de procesos
- Visualización del tiempo de actividad del sistema (Uptime)
Requisitos
- Python 3.6 o superior
- Sistema operativo Linux
Cómo ejecutar
Simplemente ejecuta el script principal:
python system_monitor.py
### Cómo funciona
Esta aplicación utiliza la biblioteca `ctypes` de Python para interactuar con las bibliotecas del sistema y acceder a información del sistema de bajo nivel. También utiliza el sistema de archivos `/proc` para recopilar métricas adicionales sobre el estado del sistema.
El monitoreo se realiza en tiempo real con actualizaciones cada 2 segundos (configurable).
### Arquitectura
La aplicación sigue un enfoque orientado a objetos con estos componentes clave:
1. **Clase SystemMonitor**: Clase principal que orquesta el monitoreo
2. **Métodos de recopilación de datos**: Métodos para recopilar diferentes métricas del sistema
3. **Métodos de visualización**: Métodos para formatear y mostrar los datos recopilados
### Extensión del monitor
Para agregar nuevas capacidades de monitoreo:
1. Crea un nuevo método en la clase `SystemMonitor` para recopilar los datos deseados
2. Actualiza el método `display_dashboard` para mostrar la nueva información
3. Asegúrate de un manejo de errores adecuado para la robustez
### Recursos de aprendizaje
- [Documentación de Python ctypes](https://docs.python.org/3/library/ctypes.html)
- [Documentación del sistema de archivos Linux Proc](https://man7.org/linux/man-pages/man5/proc.5.html)
### Revisión y resumen
Revisemos lo que hemos logrado en este laboratorio:
1. Aprendimos a usar la biblioteca `ctypes` de Python para interactuar con las bibliotecas del sistema
2. Exploramos los tipos de datos y estructuras C en Python
3. Creamos varias aplicaciones prácticas:
- Recuperación básica de información del sistema
- Monitoreo de procesos
- Utilidades de tiempo
- Demostración de gestión de memoria
- Monitor del sistema completo
4. Aprendimos a:
- Cargar bibliotecas dinámicas
- Llamar a funciones C desde Python
- Definir y manipular estructuras C
- Trabajar con punteros y direcciones de memoria
- Manejar errores a nivel del sistema
Estas habilidades forman la base para trabajar con la API de Windows al desarrollar en sistemas Windows. Los principios siguen siendo los mismos: cargarás bibliotecas específicas de Windows (como kernel32.dll, user32.dll, etc.) en lugar de libc, pero el enfoque para definir estructuras, llamar a funciones y manejar los datos sigue siendo consistente.
Resumen
En este laboratorio, has aprendido a usar la biblioteca ctypes de Python para interactuar con las bibliotecas del sistema y realizar operaciones a nivel del sistema. Si bien el laboratorio se realizó en un entorno Linux, los principios y técnicas que has aprendido también se aplican directamente a la programación de la API de Windows.
Puntos clave de este laboratorio:
Comprensión de los fundamentos de ctypes: Has aprendido a cargar bibliotecas dinámicas, definir tipos de datos C y llamar a funciones del sistema desde Python.
Trabajo con estructuras C: Has dominado la creación y manipulación de estructuras C en Python, esencial para intercambiar datos complejos con las bibliotecas del sistema.
Gestión de memoria: Has obtenido información sobre la asignación de memoria, los punteros y la gestión de memoria al trabajar con bibliotecas del sistema.
Creación de aplicaciones prácticas: Has aplicado tus conocimientos para crear aplicaciones útiles, culminando en un monitor del sistema completo.
Integración del sistema: Has visto cómo Python se puede integrar con la funcionalidad del sistema de bajo nivel a través del puente
ctypes.
Estas habilidades proporcionan una base sólida para desarrollar aplicaciones que necesitan interactuar con el sistema operativo a un nivel bajo, ya sea en Linux o Windows. Al trabajar en sistemas Windows, usarías el mismo enfoque pero con bibliotecas y funciones de la API específicas de Windows.
El aprendizaje adicional podría implicar la exploración de las API específicas de Windows para la gestión de ventanas, interfaces gráficas, servicios del sistema o capacidades de red utilizando las técnicas que has aprendido en este laboratorio.



