Введение
Этот подробный учебник проведет вас через использование библиотеки ctypes Python для взаимодействия с Windows API. Вы узнаете, как получить доступ к функциональности системы Windows, управлять процессами и использовать специфические для Windows функции непосредственно из Python. К концу этой лабораторной работы вы поймете, как создавать приложения, которые могут беспрепятственно интегрироваться с операционной системой Windows и выполнять мощные операции на системном уровне.
Понимание библиотеки ctypes Python
На этом этапе мы рассмотрим основы библиотеки ctypes Python, которая служит основой для взаимодействия с Windows API. Библиотека ctypes действует как мост между Python и нативными библиотеками C, позволяя нам вызывать функции непосредственно из DLL (Dynamic Link Libraries - библиотеки динамической компоновки).
Что такое ctypes?
ctypes - это библиотека внешних функций для Python, которая предоставляет типы данных, совместимые с C, и позволяет вызывать функции в DLL или общих библиотеках. Она особенно полезна для:
- Доступа к низкоуровневым системным функциям
- Взаимодействия с оборудованием
- Вызова функций из платформ-специфичных библиотек
Установка необходимых пакетов
Прежде чем мы начнем писать код, давайте установим необходимые пакеты. Откройте терминал в WebIDE и выполните:
pip install pywin32-ctypes
Это установит совместимую библиотеку, которая работает с нашей средой.
Основное использование ctypes
Давайте создадим простой скрипт Python, чтобы понять, как работает ctypes. В WebIDE создайте новый файл с именем ctypes_basics.py в каталоге /home/labex/project со следующим содержимым:
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")
Запустите скрипт, используя:
python3 ctypes_basics.py
Вы должны увидеть вывод, похожий на этот:
Random number from C library: 1804289383
Size of int: 4 bytes
C-compatible string: Hello from ctypes!
String buffer size: 19 bytes
Понимание типов данных C в Python
ctypes предоставляет обертки, совместимые с Python, для типов данных C. Вот справочная таблица распространенных типов данных C и их эквивалентов ctypes:
| Тип C | Тип ctypes | Тип Python |
|---|---|---|
| char | c_char | 1-символьный объект bytes |
| int | c_int | int |
| unsigned int | c_uint | int |
| long | c_long | int |
| void * | c_void_p | int или None |
| char * | c_char_p | bytes или None |
| wchar_t * | c_wchar_p | str или None |
Давайте рассмотрим эти типы данных на другом примере. Создайте файл с именем 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)])
Запустите скрипт:
python3 ctypes_types.py
Ожидаемый вывод:
Integer: 42, Unsigned Integer: 123
Float: 3.140000104904175, Double: 2.71828
Character: A, String: Hello, World!
Array elements: [1, 2, 3, 4, 5]
Это базовое понимание ctypes поможет нам при дальнейшем взаимодействии с более сложными системными библиотеками и, в частности, с Windows API.
Доступ к системным библиотекам с помощью ctypes
На этом этапе мы узнаем, как получить доступ к системным библиотекам и вызывать их функции с помощью ctypes. Поскольку мы работаем в среде Linux, мы сосредоточимся на системных библиотеках Linux, объясняя при этом принципы, которые также применимы к доступу к Windows API.
Загрузка динамических библиотек
В Python мы можем загружать динамические библиотеки, используя несколько методов, предоставляемых ctypes:
CDLL- для загрузки стандартных библиотек CWinDLL- для загрузки DLL Windows (при работе в Windows)OleDLL- для загрузки COM-библиотек (при работе в Windows)
Давайте создадим файл с именем system_info.py, чтобы изучить информацию о системе, используя стандартные библиотеки:
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}")
Запустите скрипт:
python3 system_info.py
Вы должны увидеть подробную информацию о вашей системе, аналогичную этой:
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
Создание монитора процессов
Теперь давайте создадим более практичное приложение: простой монитор процессов, который будет отображать список запущенных процессов. Создайте файл с именем 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")
Запустите монитор процессов:
python3 process_monitor.py
Вы должны увидеть вывод, похожий на этот, который будет обновляться каждые 3 секунды:
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
...
Дайте монитору процессов поработать около 10 секунд, затем нажмите Ctrl+C, чтобы остановить его.
В этих примерах мы узнали, как:
- Загружать и использовать системные библиотеки с помощью
ctypes - Получать доступ к информации о системе
- Создать практичный инструмент мониторинга процессов
Эти принципы те же, которые вы будете использовать для взаимодействия с Windows API через ctypes, только с другими именами библиотек и вызовами функций.
Создание и использование структур C с помощью ctypes
На этом этапе мы узнаем, как определять и использовать структуры C в Python. Структуры необходимы при работе с системными API, поскольку они обычно используются для обмена данными между Python и системными библиотеками.
Понимание структур C в Python
Структуры C могут быть представлены в Python с использованием класса ctypes.Structure. Это позволяет нам создавать сложные структуры данных, которые соответствуют макету памяти, ожидаемому функциями C.
Давайте создадим файл с именем struct_example.py, чтобы изучить, как работать со структурами:
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}")
Запустите скрипт:
python3 struct_example.py
Вы должны увидеть вывод, похожий на этот:
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
Создание утилиты системного времени
Теперь давайте создадим практическое приложение, которое использует структуры C для взаимодействия с функциями системного времени. Создайте файл с именем 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()}")
Запустите утилиту времени:
python3 time_utility.py
Вы должны увидеть вывод, похожий на этот:
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
Понимание управления памятью с помощью ctypes
При работе с ctypes и структурами C важно понимать управление памятью. Давайте создадим еще один пример, memory_management.py, чтобы продемонстрировать это:
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()
Запустите скрипт управления памятью:
python3 memory_management.py
Вы должны увидеть вывод, похожий на этот:
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...
В этих примерах мы узнали, как:
- Определять и использовать структуры C в Python с помощью
ctypes - Создавать указатели на структуры и получать доступ к их содержимому
- Создавать вложенные структуры и массивы структур
- Создавать практические приложения, используя функции системного времени
- Управлять памятью при работе с
ctypes
Эти навыки необходимы при работе с функциями Windows API, которые часто требуют сложных структур данных для передачи информации туда и обратно.
Создание полноценного приложения для мониторинга системы
На этом заключительном этапе мы объединим все наши знания, чтобы создать комплексное приложение для мониторинга системы. Это приложение будет использовать ctypes для сбора информации о системе, отображения метрик в реальном времени и демонстрации того, как структурировать более крупное приложение Python, которое взаимодействует с системными библиотеками.
Создание монитора системы
Создайте новый файл с именем system_monitor.py со следующим содержимым:
import ctypes
import os
import time
import platform
from datetime import datetime
class SystemMonitor:
"""System monitoring application using ctypes"""
def __init__(self):
"""Initialize the system monitor"""
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()
Запустите монитор системы:
python3 system_monitor.py
Монитор системы будет отображать информацию о вашей системе в реальном времени, обновляя ее каждые 2 секунды. Вы должны увидеть панель мониторинга с:
- Временем безотказной работы системы
- Использованием CPU
- Информацией о памяти (всего, использовано, доступно)
- Использованием диска
- Количеством процессов
Дайте монитору поработать несколько мгновений, чтобы наблюдать, как меняются метрики, затем нажмите Ctrl+C, чтобы выйти.
Понимание структуры монитора системы
Давайте разберем ключевые компоненты нашего монитора системы:
- Структура класса: Использование объектно-ориентированного программирования для организации нашего кода
- Организация методов: Разделение функциональности на отдельные методы
- Обработка ошибок: Использование блоков try-except для обработки потенциальных ошибок
- Форматирование данных: Преобразование необработанных данных в удобочитаемые форматы
- Обновления в реальном времени: Использование цикла с time.sleep() для периодических обновлений
Добавление документации
Теперь давайте добавим файл документации для нашего монитора системы. Создайте файл с именем README.md:
Python System Monitor
Комплексное приложение для мониторинга системы, построенное на Python с использованием ctypes для взаимодействия с системой.
Функции
- Мониторинг использования CPU в реальном времени
- Отслеживание использования памяти
- Анализ дискового пространства
- Подсчет процессов
- Отображение времени безотказной работы системы
Требования
- Python 3.6 или выше
- Операционная система Linux
Как запустить
Просто выполните основной скрипт:
python system_monitor.py
### Как это работает
Это приложение использует библиотеку `ctypes` Python для взаимодействия с системными библиотеками и доступа к низкоуровневой информации о системе. Оно также использует файловую систему `/proc` для сбора дополнительных метрик о состоянии системы.
Мониторинг происходит в реальном времени с обновлениями каждые 2 секунды (настраивается).
### Архитектура
Приложение следует объектно-ориентированному подходу со следующими ключевыми компонентами:
1. **Класс SystemMonitor**: Основной класс, который координирует мониторинг
2. **Методы сбора данных**: Методы для сбора различных системных метрик
3. **Методы отображения**: Методы для форматирования и отображения собранных данных
### Расширение монитора
Чтобы добавить новые возможности мониторинга:
1. Создайте новый метод в классе `SystemMonitor` для сбора нужных данных
2. Обновите метод `display_dashboard`, чтобы отобразить новую информацию
3. Обеспечьте надлежащую обработку ошибок для надежности
### Ресурсы для обучения
- [Документация Python ctypes](https://docs.python.org/3/library/ctypes.html)
- [Документация Linux Proc Filesystem](https://man7.org/linux/man-pages/man5/proc.5.html)
### Обзор и резюме
Давайте рассмотрим, чего мы достигли в этой лабораторной работе:
1. Мы узнали, как использовать библиотеку `ctypes` Python для взаимодействия с системными библиотеками
2. Мы изучили типы данных и структуры C в Python
3. Мы создали несколько практических приложений:
- Получение базовой информации о системе
- Мониторинг процессов
- Утилиты времени
- Демонстрация управления памятью
- Комплексный монитор системы
4. Мы узнали, как:
- Загружать динамические библиотеки
- Вызывать функции C из Python
- Определять и манипулировать структурами C
- Работать с указателями и адресами памяти
- Обрабатывать ошибки на системном уровне
Эти навыки составляют основу для работы с Windows API при разработке в системах Windows. Принципы остаются прежними - вы будете загружать библиотеки, специфичные для Windows (например, kernel32.dll, user32.dll и т. д.) вместо libc, но подход к определению структур, вызову функций и обработке данных остается неизменным.
Резюме
В этой лабораторной работе вы узнали, как использовать библиотеку ctypes Python для взаимодействия с системными библиотеками и выполнения операций на системном уровне. Хотя лабораторная работа проводилась в среде Linux, принципы и методы, которые вы изучили, также напрямую применимы к программированию Windows API.
Основные выводы из этой лабораторной работы:
Понимание основ ctypes: Вы узнали, как загружать динамические библиотеки, определять типы данных C и вызывать системные функции из Python.
Работа со структурами C: Вы освоили создание и манипулирование структурами C в Python, что необходимо для обмена сложными данными с системными библиотеками.
Управление памятью: Вы получили представление о выделении памяти, указателях и управлении памятью при работе с системными библиотеками.
Создание практических приложений: Вы применили свои знания для создания полезных приложений, кульминацией которых стал комплексный монитор системы.
Системная интеграция: Вы увидели, как Python может быть интегрирован с низкоуровневой функциональностью системы через мост
ctypes.
Эти навыки обеспечивают прочную основу для разработки приложений, которым необходимо взаимодействовать с операционной системой на низком уровне, будь то Linux или Windows. При работе в системах Windows вы будете использовать тот же подход, но с библиотеками и функциями API, специфичными для Windows.
Дальнейшее обучение может включать изучение API, специфичных для Windows, для управления окнами, графическими интерфейсами, системными службами или сетевыми возможностями, используя методы, которые вы изучили в этой лабораторной работе.



