Тестовое задание от лаборатории компьютерного моделирования SimLab на позицию Python-разработчика 👇🏻
✴️ Суть: Необходимо написать два консольных приложения на Python.
1️⃣ Первое рекурсивно каждые 2 секунды сканирует определенную папку на жёстком диске (папка передается через аргумент приложения) и передает через TCP-соединение второму приложению (ip-адрес и порт передаются через аргумент) путь и размер файлов при их изменении (в том числе появлении и удалении) в папке. 2️⃣ Второе приложение принимает все TCP-соединения от любого количества запущенных первых приложений (параллельно) и выводит путь к файлу, размер и тип изменения (новый файл, удаленный файл, измененный файл) в консоль, добавляя информацию о времени, когда было получено сообщение.
✍🏼 Пример использования: Первое приложение запускается на наборе рабочих станций, которые нам интересны. Второе приложение запускается на рабочей станции системного администратора для анализа поведения пользователей в определенной (у каждого своя) папки на их компьютерах.
❗️Требования: 🔹 ОС – любая; 🔹 файлы могут быть любого размера; 🔹 можно использовать любые пакеты Python.
➕ Плюсик в карму, если добавите поддержку кириллических имён файлов.
#тестовое | 🍩 Поддержать канал 🫶
· 17.01.2025
1. scanner.py (сканер директории): import os import time import socket import json import hashlib import argparse import logging import platform import errno
def get_file_hash(filepath): """Вычисляет хэш файла.""" try: with open(filepath, 'rb') as f: file_hash = hashlib.md5() for chunk in iter(lambda: f.read(4096), b""): file_hash.update(chunk) return file_hash.hexdigest() except OSError as e: if e.errno == errno.EACCES: # Обработка ошибки доступа logging.warning(f"Нет доступа к файлу {filepath}: {e}") else: logging.error(f"Ошибка при обработке файла {filepath}: {e}") return None
def scan_directory(directory, server_ip, server_port): """Сканирует директорию и отправляет изменения на сервер.""" previous_files = {} while True: current_files = {} try: for root, _, files in os.walk(directory): for filename in files: filepath = os.path.join(root, filename) file_hash = get_file_hash(filepath) if file_hash: try: current_files[filepath] = (os.path.getsize(filepath), file_hash) except OSError as e: # Обработка ошибок размера файла logging.error(f"Ошибка получения размера файла {filepath}: {e}") continue except OSError as e: logging.error(f"Ошибка при обходе директории {directory}: {e}") return
def send_message(server_ip, server_port, filepath, size, change_type): """Отправляет сообщение на сервер.""" try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.settimeout(5) sock.connect((server_ip, server_port)) message = {"path": filepath, "size": size, "type": change_type} json_message = json.dumps(message, ensure_ascii=False).encode('utf-8') try: sock.sendall(json_message) except OSError as e: logging.error(f"Ошибка отправки данных сокета: {e}") sock.close() # Закрываем сокет при ошибке отправки return except (socket.timeout, ConnectionRefusedError, OSError) as e: logging.error(f"Ошибка подключения/отправки: {e}")
if name == "main": parser = argparse.ArgumentParser(description="Сканер директории.") parser.add_argument("directory", help="Директория для сканирования.") parser.add_argument("server_ip", help="IP-адрес сервера.") parser.add_argument("server_port", type=int, help="Порт сервера.") args = parser.parse_args()
2. server.py (сервер): import socket import json import threading import datetime import logging import platform import traceback
def handle_client(conn, addr): """Обрабатывает подключение клиента.""" try: while True: data = conn.recv(4096) if not data: break try: message = json.loads(data.decode('utf-8')) timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") print(f"[{timestamp}] {message['path']} ({message['size']} bytes) - {message['type']}") except (json.JSONDecodeError, UnicodeDecodeError) as e: logging.error(f"Ошибка декодирования сообщения от {addr}: {e}") traceback.print_exc() # Вывод полного traceback break except (ConnectionResetError, ConnectionAbortedError, OSError) as e: logging.info(f"Клиент {addr} отключился: {e}") except Exception as e: logging.error(f"Необработанная ошибка при обработке клиента {addr}: {e}") traceback.print_exc() finally: conn.close()
def start_server(port): """Запускает сервер.""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.bind(('', port)) sock.listen() logging.info(f"Сервер запущен на порту {port}.") while True: try: conn, addr = sock.accept() logging.info(f"Подключился клиент: {addr}") client_thread = threading.Thread(target=handle_client, args=(conn, addr), daemon=True) client_thread.start() except KeyboardInterrupt: print("Сервер остановлен.") break except OSError as e: logging.error(f"Ошибка при подключении клиента: {e}")
if name == "main": import argparse parser = argparse.ArgumentParser(description="Сервер для получения изменений файлов.") parser.add_argument("port", type=int, help="Порт сервера.") args = parser.parse_args()
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён